游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

vue的两种服务器端渲染方案

  作者:京东零售姜欣
  关于服务器端渲染方案,之前只接触了基于react的Next。js,最近业务开发vue用的比较多,所以调研了一下vue的服务器端渲染方案。首先:长文预警,下文包括了两种方案的实践,没有耐心的小伙伴可以直接跳到方案标题下,down代码体验一下。前置知识:1、什么是服务器端渲染(ssr)?
  简单来说就是用户第一次请求页面时,页面上的内容是通过服务器端渲染生成的,浏览器直接显示服务端返回的完整html就可以,加快首屏显示速度。
  举个栗子:
  当我们访问一个商品列表时,如果使用客户端渲染(csr),浏览器会加载空白的页面,然后下载js文件,通过js在客户端请求数据并渲染页面。如果使用服务器端渲染(ssr),在请求商品列表页面时,服务器会获取所需数据并将渲染后的HTML发送给浏览器,浏览器一步到位直接展示,而不用等待数据加载和渲染,提高用户的首屏体验。2、服务器端渲染的优缺点
  优点:
  (1)更好的seo:抓取工具可以直接查看完全渲染的页面。现在比较常用的交互是页面初始展示loading菊花图,然后通过异步请求获取内容,但是但抓取工具并不会等待异步完成后再行抓取页面内容。
  (2)内容到达更快:不用等待所有的js都完成下载并执行,所以用户会更快速地看到完整渲染的页面。
  缺点:
  (1)服务器渲染应用程序,需要处于Node。jsserver运行环境
  (2)开发成本比较高
  总结:
  总得来说,决定是否使用服务器端渲染,取决于具体的业务场景和需求。对于具有大量静态内容的简单页面,客户端渲染更合适一些,因为它可以更快地加载页面。但是对于需要从服务器动态加载数据的复杂页面,服务器端渲染可能是一个更好的选择,因为他可以提高用户的首屏体验和搜索引擎优化。
  下面进入正文方案一:vue插件vueserverrender
  git示例demo地址
  结论前置:不建议用,配置成本高
  官网地址:https:v2。ssr。vuejs。orgzh
  首先要吐槽一下官网,按官网教程比较难搞,目录安排的不太合理,一顿操作项目都没起来。。。
  并且官网示例的构建配置代码是webpack4的,现在初始化项目后基本安装的都是webpack5,有一些语法不同(1)首先,先初始化一个npm项目,然后安装依赖得到一个基础项目。(此处要注意vueserverrenderer和vue必须匹配版本)npminityyarnaddvuevueserverrendererSyarnaddexpressSyarnaddwebpackwebpackclifriendlyerrorswebpackpluginvueloaderbabelloaderbabelcoreurlloaderfileloadervuestyleloadercssloadersassloadersasswebpackmergewebpacknodeexternalsDyarnaddcleanwebpackpluginbabelpresetenvDyarnaddrimraf模拟linx的删除命令,在build时先删除distyarnaddwebpackdevmiddlewarewebpackhotmiddlewareDyarnaddchokidarD监听变化yarnaddmemoryfsDyarnaddnodemonD。。。实在太多,如有缺失可以在package。json中查找另外:我现在用的vueloader:15。9。0版本,之前用的是vueloader:17。0。1,报了一个styles的错(2)配置app。js,entryclient。js,entryserver。js,将官网参考中的示例代码拷贝至对应文件。
  app。jsimportVuefromvueimportAppfrom。App。vueimport{createRouter}from。routerimport{createStore}from。storeimport{sync}fromvuexroutersync导出一个工厂函数,用于创建新的应用程序、router和store实例exportfunctioncreateApp(){创建router和store实例constroutercreateRouter()conststorecreateStore()sync(store,router)constappnewVue({router,store,render:hh(App)})return{app,router,store}}
  entryclient。jsimportVuefromvueimport{createApp}from。appVue。mixin({beforeMount(){const{asyncData}this。optionsif(asyncData){this。dataPromiseasyncData({store:this。store,route:this。route})}}})const{app,router,store}createApp()if(window。INITIALSTATE){store。replaceState(window。INITIALSTATE)}router。onReady((){在初始路由resolve后执行,使用router。beforeResolve(),以便确保所有异步组件都resolve。router。beforeResolve((to,from,next){constmatchedrouter。getMatchedComponents(to)constprevMatchedrouter。getMatchedComponents(from)找出两个匹配列表的差异组件letdiffedfalseconstactivatedmatched。filter((c,i){returndiffed(diffed(prevMatched〔i〕!c))})if(!activated。length){returnnext()}Promise。all(activated。map(c{if(c。asyncData){returnc。asyncData({store,route:to})}}))。then((){next()})。catch(next)})app。mount(app)})
  entryserver。jsimport{createApp}from。appexportdefaultcontext{返回一个promise,服务器能够等待所有的内容在渲染前,已经准备就绪,returnnewPromise((resolve,reject){const{app,router,store}createApp()router。push(context。url)router。onReady((){constmatchedComponentsrouter。getMatchedComponents()if(!matchedComponents。length){returnreject({code:404})}对所有匹配的路由组件调用asyncData()Promise。all(matchedComponents。map(Component{if(Component。asyncData){returnComponent。asyncData({store,route:router。currentRoute})}}))。then((){context。statestore。stateresolve(app)})。catch(reject)},reject)})}(3)在根目录下创建server。js文件
  其中一个非常重要的api:createBundleRenderer,这个api上面有一个方法renderToString将代码转化成html字符串,主要功能就是把用webpack把打包后的服务端代码渲染出来。具体了解可看官网bundlerenderer指引。server。jsconstapprequire(express)()const{createBundleRenderer}require(vueserverrenderer)constfsrequire(fs)constpathrequire(path)constresolvefilepath。resolve(dirname,file)constisProdprocess。env。NODEENEproductionconstcreateRenderer(bundle,options){returncreateBundleRenderer(bundle,Object。assign(options,{basedir:resolve(。dist),runInNewContext:false,}))}letrenderer,readyPromiseconsttemplatePathresolve(。srcindex。template。html)if(isProd){constbundlerequire(。distvuessrserverbundle。json)constclientManifestrequire(。distvuessrclientmanifest。json)consttemplatefs。readFileSync(templatePath,utf8)renderercreateRenderer(bundle,{推荐template,(可选)页面模板clientManifest(可选)客户端构建manifest})}else{开发模式readyPromiserequire(。configsetupdevserver)(app,templatePath,(bundle,options){renderercreateRenderer(bundle,options)})}constrender(req,res){constcontext{title:hellossrwithwebpack,meta:metacharsetUTF8metanameviewportcontentwidthdevicewidth,initialscale1。0metahttpequivXUACompatiblecontentieedge,url:req。url}renderer。renderToString(context,(err,html){if(err){if(err。code404){res。status(404)。end(Pagenotfound)}else{res。status(500)。end(InternalServerError)}}else{res。end(html)}})}在服务器处理函数中app。get(,isProd?render:(req,res){readyPromise。then(()render(req,res))})app。listen(8080)监听的是8080端口(4)接下来是config配置
  在根目录新增config文件夹,然后新增四个配置文件:webpack。base。config,webpack。client。config,webpack。server。config,setupdevserver(此方法是一个封装,为了配置个热加载,差点没搞明白,参考了好多)(官网传送门:构建配置)
  大部分官网有示例代码,但是要在基础上进行一些更改
  webpack。base。configwebpack。base。configconstpathrequire(path)用来处理后缀为。vue的文件const{VueLoaderPlugin}require(vueloader)constFriendlyErrorsWebpackPluginrequire(friendlyerrorswebpackplugin)定位到根目录constresolve(dir)path。join(path。resolve(dirname,。。),dir)打包时会先清除一下const{CleanWebpackPlugin}require(cleanwebpackplugin)constisProdprocess。env。NODEENVproductionmodule。exports{mode:isProd?production:development,output:{path:resolve(dist),publicPath:dist,filename:〔name〕。〔chunkhash〕。js},resolve:{alias:{public:resolve(public)}},module:{noParse:es6promise。js,rules:〔{test:。vue,loader:vueloader,options:{compilerOptions:{preserveWhiteSpace:false}}},{test:。js,loader:babelloader,exclude:nodemodules},{test:。(pngjpggifsvg),loader:urlloader,options:{limit:10000,name:〔name〕。〔ext〕?〔hash〕}},{test:。s(ac)ss?,use:〔vuestyleloader,cssloader,sassloader〕}〕},performance:{hints:false},plugins:〔newVueLoaderPlugin(),编译后的友好提示,比如编译完成或者编译有错误newFriendlyErrorsWebpackPlugin(),打包时会先清除一下newCleanWebpackPlugin()〕}
  webpack。client。configwebpack。client。configconst{merge}require(webpackmerge)constbaseConfigrequire(。webpack。base。config。js)constVueSSRClientPluginrequire(vueserverrendererclientplugin)module。exportsmerge(baseConfig,{entry:{app:。srcentryclient。js},optimization:{重要信息:这将webpack运行时分离到一个引导chunk中,以便可以在之后正确注入异步chunk。这也为你的应用程序vendor代码提供了更好的缓存。splitChunks:{name:manifest,minChunks:Infinity}},plugins:〔此插件在输出目录中生成vuessrclientmanifest。json。newVueSSRClientPlugin()〕})
  webpack。server。configwebpack。server。configconst{merge}require(webpackmerge)constnodeExternalsrequire(webpacknodeexternals)webpack的基础配置,比如sass,less预编译等constbaseConfigrequire(。webpack。base。config。js)constVueSSRServerPluginrequire(vueserverrendererserverplugin)module。exportsmerge(baseConfig,{将entry指向应用程序的serverentry文件entry:。srcentryserver。js,target:node,对bundlerenderer提供sourcemap支持devtool:sourcemap,此处告知serverbundle使用Node风格导出模块(Nodestyleexports)output:{libraryTarget:commonjs2},https:webpack。js。orgconfigurationexternalsfunctionhttps:github。comliadywebpacknodeexternals外置化应用程序依赖模块。可以使服务器构建速度更快,并生成较小的bundle文件。externals:nodeExternals({不要外置化webpack需要处理的依赖模块。你可以在这里添加更多的文件类型。例如,未处理。vue原始文件,你还应该将修改global(例如polyfill)的依赖模块列入白名单allowlist:。css}),这是将服务器的整个输出构建为单个JSON文件的插件。默认文件名为vuessrserverbundle。jsonplugins:〔newVueSSRServerPlugin()〕})
  setupdevserver:封装createRenderer方法constwebpackrequire(webpack)constfsrequire(fs)constpathrequire(path)constchokidarrequire(chokidar)constmiddlewarerequire(webpackdevmiddleware)constHMRrequire(webpackhotmiddleware)constMFSrequire(memoryfs)constclientConfigrequire(。webpack。client。config)constserverConfigrequire(。webpack。server。config)constreadFile(fs,file){try{returnfs。readFileSync(path。join(clientConfig。output。path,file),utf8)}catch(error){}}constsetupServer(app,templatePath,cb){letbundleletclientManifestlettemplateletreadyconstreadyPromisenewPromise(rreadyr)templatefs。readFileSync(templatePath,utf8)constupdate(){if(bundleclientManifest){通知server进行渲染执行createRendererRenderToStringready()cb(bundle,{template,clientManifest})}}webpackentryserverbundleconstmfsnewMFS();constserverCompilerwebpack(serverConfig);serverCompiler。outputFileSystemmfs;serverCompiler。watch({},(err,stats){if(err)throwerr之后读取输出:statsstats。toJson()stats。errors。forEach(errconsole。error(err))stats。warnings。forEach(errconsole。warn(err))if(stats。errors。length)returnbundleJSON。parse(readFile(mfs,vuessrserverbundle。json))update()});clientConfig。plugins。push(newwebpack。HotModuleReplacementPlugin())clientConfig。entry。app〔webpackhotmiddlewareclient,clientConfig。entry。app〕clientConfig。output。filename〔name〕。jsconstclientCompilerwebpack(clientConfig);constdevMiddlewaremiddleware(clientCompiler,{noInfo:true,publicPath:clientConfig。output。publicPath,logLevel:silent})app。use(devMiddleware);app。use(HMR(clientCompiler));clientCompiler。hooks。done。tap(clientsBuild,stats{statsstats。toJson()stats。errors。forEach(errconsole。error(err))stats。warnings。forEach(errconsole。warn(err))if(stats。errors。length)returnclientManifestJSON。parse(readFile(devMiddleware。fileSystem,vuessrclientmanifest。json))update()})fstemplatePathtemplatechokidar。watch(templatePath)。on(change,(){templatefs。readFileSync(templatePath,utf8)console。log(templateisupdated);update()})returnreadyPromise}module。exportssetupServer(5)配置搞完了接下来是代码渲染
  在src目录下,新增index。template。html文件,将官网中的例子(地址:使用一个页面模板)复制,并进行一些更改htmlhead!使用双花括号(doublemustache)进行HTML转义插值(HTMLescapedinterpolation)title{{title}}title!使用三花括号(triplemustache)进行HTML不转义插值(nonHTMLescapedinterpolation){{{meta}}}headbody!这个是告诉我们在哪里插入正文的内容!vuessroutletbodyhtml(6)再搞个store和api模拟一下数据请求
  这里介绍一下一个很重要的东西asyncData预取数据,预取数据是在vue挂载前,所以下文这里用了上下文来获取store而不是thisasyncData:({store}){returnstore。dispatch(getDataAction)},
  在src下创建api文件夹,并在下面创建data。js文件data。jsconstgetData()newPromise((resolve){setTimeout((){resolve(〔{id:1,item:测试1},{id:2,item:测试2},〕)},1000)})export{getData}
  在src下创建store文件夹,并在下面创建index。js文件store。jsimportVuefromvueimportVuexfromvuexVue。use(Vuex)import{getData}from。。apidataexportfunctioncreateStore(){returnnewVuex。Store({state:{lists:〔〕},actions:{getDataAction({commit}){returngetData()。then((res){commit(setData,res)})}},mutations:{setData(state,data){state。listsdata}}})}(7)编写组件,在srccomponents文件夹下写两个组件,在app。vue中引用一下,用上刚写的模拟数据
  Hello。vuetemplate这里是测试页面一p{{item}}routerlinktohello1链接到测试页面二routerlinktemplatestylelangscssscopedstyle
  Hello1。vuetemplate这里是测试页面二{{item}}templatestylelangscssscopedstyle(8)配置路由并在app。vue使用路由
  router。jsimportVuefromvueimportRouterfromvuerouterVue。use(Router)exportfunctioncreateRouter(){returnnewRouter({mode:history,routes:〔{path:hello,component:()import(。componentsHello。vue)},{path:hello1,component:()import(。componentsHello1。vue)},〕})}
  app。vuetemplaterouterviewrouterviewtemplatestylelangscssscopedstyle(9)根目录下创建一个。babelrc,进行配置{presets:〔〔babelpresetenv,{modules:false}〕〕}(10)改写package。json执行命令dev:nodemonserver。js,build:rimrafdistnpmrunbuild:clientnpmrunbuild:server,build:client:webpackconfigconfigwebpack。client。config。js,build:server:webpackconfigconfigwebpack。server。config。js
  大搞告成,执行一下dev命令,可以通过访问localhost:8080端口看到页面,记得带上路由哦
  执行build命令可看到,最后dist文件下共有三个文件:main。〔chunkhash〕。js,vuessrclientmanifest。json,vuessrserverbundle。json
  附上文件整体目录结构
  方案二:基于vue的nuxt。js通用应用框架
  git示例demo地址
  一对比,这个就显得丝滑多了官网地址:nuxt。js
  先对比一下两种方案的差别1。vue初始化虽然有cli,但是nuxt。js的cli更加完备2。nuxt有更合理的工程化目录,vue过于简洁,比如一些component,api文件夹都是要手动创建的3。路由配置:传统应用需要自己来配置,nuxt。js自动生成4。没有统一配置,需手动创建。nuxt。js会生成nuxt。config。js5。传统不易与管理底层框架逻辑(nuxt支持中间件管理,虽然我还没探索过这里)
  显而易见这个上手就快多了,也不需要安装一大堆依赖,如果用了sass需要安装sass和sassloader,反正我是用了(1)创建一个项目可选npm,npx,yarn,具体看官方文档npminitnuxtappprojectname(2)pages下面创建几个文件
  nuxt是通过pages页面形成动态的路由,不用手动配置路由。比如在pages下面新增了个文件about。vue,那么这个页面对应的路由就是about
  其实这个时候运行npmrundev就可以看到简单的页面了(3)模拟接口
  这里介绍一个插件,可以快速创建一个服务npmijsonserver
  安装完后,在根目录新增db。json文件,模拟几个接口{post:〔{id:1,title:jsonserver,author:jx}〕,comments:〔{id:1,body:somecomment,postId:1}〕,profile:{name:typicode}}
  运行命令jsonserverwatchdb。jsonport8000(不加会端口冲突),就可以看到
  因为是get请求,可以直接点击访问可以看到mock的数据已经返回了
  (4)页面调用
  先配置一下axios,推荐使用nuxt。js封装的axios:nuxtjsaxios:5。13。6,然后再在nuxt。config。js文件中modules下面配置一下就可以使用了modules:〔nuxtjsaxios〕,
  随便找个接口调用一下template这里是测试页面一接口返回数据:{{posts}}template
  刷新下页面就可以看到效果了,这里注意axios有两个get方法,一个axios。get还会返回头部等信息,另一个axios。get只返回结果
  总结:
  从页面篇幅上应该也能看到哪个容易上手了,nuxt相对于插件来说限定了文件夹的结构,并通过此预定了一些功能,更好上手。预设了利用vue。js开发服务端渲染所需要的各种配置,并且提供了提供了静态站点,异步数据加载,中间件支持,布局支持等

iOS限免App精选健康记录工具血压日记(16560)IT之家7月26日消息今天小编给IT之家小伙伴带来的iOS限免App是《血压日记》,这款App无广告,可以记录血压和心率。AppStore《血压日记》这款应用可以快……iOS限免App精选快速拍照工具FastCamera(165IT之家7月26日消息今天小编给IT之家小伙伴带来的iOS限免App是《FastCamera》,这是一款拍照摄影类应用,可高速摄影、延迟摄影等。AppStore《Fast……苹果新隐私功能重创广告商收入下降15到20北京时间7月14日早间消息,据报道,一位移动营销主管称,苹果的应用跟踪透明功能导致iOS广告商的收入下降15到20。在一次采访中,消费者获取(ConsumerAcquis……阿里系淘宝闲鱼支付宝京东拼多多等App开屏启动加快,无广告弹IT之家7月8日消息据不少网友反馈,近期阿里系旗下的淘宝、闲鱼、支付宝等App启动速度加快十分明显,IT之家特意在iPhone上测试了一下,发现这些App启动页在今天变得十分清……库克iPhone在印度只占很少的份额,苹果将开设零售店来抢占北京时间9月18日消息,苹果公司在周五举行全体员工大会,CEO蒂姆库克(TimCook)就员工关心的问题进行了回答,涉及与游戏开发商Epic的诉讼案、薪酬不平、以及苹果未来的计……京东苹果超品日享5重福利,AirPodsPro低至1599元京东12月14日苹果超级品牌日,专享五重福利,含以旧换新至高补贴3000元、指定iPhone领券减500元享12期免息、macbook新品专属30天无忧试用365天全保换新36……异性之间,有这3个迹象,就是遇见灵魂伴侣了两个人在一起的时候,若是彼此看对方不顺眼,常会一些小事而争吵,彼此并不愿意让着对方,将生活过成一地鸡毛。抑或,两个人虽然生活在同一个屋檐下,却各忙各的,各玩各的,他们虽然……苹果iPhone13mini13ProProMax国行售价公IT之家9月15日消息在今晚的苹果发布会上,苹果正式推出了iPhone13mini、13、Pro、ProMax四款机型,现在该系列机型的国行售价已经公布。iPhone13min……iPhone14上市时间现在果粉最关心的,就是iPhone14的售价,以及准确上市时间,小编来说说:苹果之前预计在9月中旬开启发布会。依据官网消息可能提前发售,这次的机型分别为:iPhone14、iP……熊梓淇方向梅妮莎小品我在等着你台词剧本笑起来真好看熊梓淇:小雅,你说当初咱俩是多么多么恩爱呀,可是你咋说不要我就不要我了呢,你说我得多伤心多难过,我多,我多,没有音乐这也哭不出来啊,手机管家。手机管家:(我在)。熊……苹果iPhone13ProMax如何使用微距模式摄影IT之家9月25日消息苹果iPhone13系列在昨日正式开售,其中,iPhone13Pro和iPhone13ProMax机型支持微距模式,这是苹果首次为iPhone用户带来微距……水果美味吃多少合适水果营养丰富,美味可口,不仅深受人们的喜爱,在膳食宝塔中也占有重要地位。孩子们都喜欢水果,吃一大盘也不在话下。有些孩子不爱吃菜,家长索性用水果代替蔬菜让孩子多吃些。这样做真的可……
人心不足蛇吞象!三连败之后,伊戈达拉直对科尔,指出勇士的软肋三连败!这样的战绩对于勇士队来说是可耻的,库里的缺阵对勇士队的影响是巨大的,但是别忘了,他们还有克莱、维金斯、普尔这样的阵容班底,为什么勇士队会有这么糟糕的表现?其实很多人都清……真空拔罐可以哪里难受拔哪里?拔罐因其具有祛湿除寒,温经通络,活血化瘀,散寒止痛的功效,成为越来越多人青睐的养生保健项目。特别是真空拔罐,较之于火罐更安全、省事,更适合居家操作。问题来了,您对真空拔罐这种操……乒乓球支线赛五冠尽归中华,冠军赛争金赛程,林高远再战张本智和北京时间7月23日凌晨,世乒联夏季欧洲系列赛高潮迭起,WTT冠军赛决赛对阵出炉:女单王曼昱VS王艺迪,男单林高远大战日本张本智和;WTT支线赛决出全部金银牌:继国乒林诗栋蒯曼夺……河北30家企业上榜!2022中国民营企业500强榜单最新发布河北新闻网9月7日讯(靳彤)今天,全国工商联发布《2022中国民营企业500强调研分析报告》。分析报告显示,河北省共有30家企业上榜2022中国民营企业500强,其中6家企业位……大年初一,这个景区人气旺原标题:大年初一,这个景区人气旺!大年初一,仙桃沔阳小镇第二届民俗文化旅游节盛大开幕,在做好疫情防控的同时,景区共接待游客7千多人,迎来虎年首日开门红。传承沔阳文化……篮网团队重组罪人1。蔡老板为首管理层,作为冠军争夺者排除质疑选择没有执教经验的菜鸟教练纳什;2。管理层操作失误,交易犹豫不决,去年躺着几千万伤病舍不得交易,最后发着工资人走了,而且关键时刻舍不……大蒜洋葱西蓝花,网上疯传的几种抗癌食物到底有没有用近些年来,随着癌症发病率的提高,抗癌食物越来越受欢迎,今天有人说大蒜能抗癌,家里做饭顿顿都有大蒜,明天又有人说西蓝花能抗癌,冰箱里的西蓝花都塞满了。可偏偏有的患者一天三顿吃大蒜……蒙脱石散脱销!二附院专家提醒,儿童腹泻还有别的药新年第一天,蒙脱石散突然冲上微博热搜,一度导致缺货。它究竟是什么药?是干什么用的?如果孩子不幸感染新冠病毒,出现了腹泻等消化道症状,还有哪些安全的止泻药可以吃呢?二附院药学专家……宇宙如此之大,为何没有高级文明通过虫洞来到地球?我们简单回顾一下费米悖论:它认为宇宙中产生了那么多星系,有那么多宜居星球,应该产生很多文明,其中应该有一些能与我们相遇,但是实际上并没有。用比较准确的数学公式,与我们通讯……王晗评价三外援首阶段表现,透露山东男篮考虑调整外援视频加载中。。。齐鲁网闪电新闻10月31日讯山东电视体育频道最新消息,CBA结束了第一阶段征程,山东男篮6胜3负,积分榜第四,这个成绩已然达到了球队赛前的预期,本赛……10首秋风诗词,秋风十里,不如想你风起了,在这个曼妙的秋天。早上吹来的风,带着丝丝凉意,午后,又在阳光中悄然而去。在秋风中,树叶黄了,大雁南飞了,人也忧伤了,头顶的明月,数着一季一季的时光,看着人间……王者荣耀S26赛季初谁将成为上分潜力股?貂蝉连吃三大红利大家好,我是秋豆。王者荣耀S26赛季将于1月6号正式更新,新赛季全部玩家都会掉段,又要重新从钻石、星耀开始冲击王者段位。那么,随着版本的变更,哪位英雄能够脱颖而出,……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网