手机版

vue项目中实现缓存的最佳方案详解

时间:2021-08-21 来源:互联网 编辑:宝哥软件园 浏览:

需求

在开发vue的项目中,有这样一个需求:一个视频列表页面,显示视频名称和是否收藏,点击一个要观看的项目,可以收藏也可以取消收藏,返回的时候需要记住列表页面的页码,这个视频的收藏状态也需要更新,但是这个页面在从其他页面进入视频列表页面的时候并没有缓存,也就是进入的时候是视频列表页面的第一页

总结一句话:页面列表-页面一个明细-页面一个列表,缓存页面一个列表,同时如果这个视频的收藏状态发生变化,其他页面-页面列表、页面列表都不会被缓存。

我在网上发现了很多别人的方法,不符合我们的需求

然后我们团队几个人努力了几天,真正想出了一套实现这个需求的方法

实现后的效果

没有图片,就没有真相。拍个gif图看看实现后的效果。

操作流程:

页面列表,跳转到第2页-页面列表,页码显示第一页,表示页面a列表是从其他页面列表进入的,页面列表不缓存,跳转到第3页,点击视频22-进入视频详情页页面尾部,点击收藏,收藏成功。点击后退-页面列表显示第三页,视频22的收藏状态由无收藏变为收藏,表示页面列表是从pageADetail进入,页面列表被缓存,状态描述更新:

二级缓存:是来自A-B-A,缓存A-B-C-B-A,缓存A和B的三级缓存,因为大部分的项目都是二级缓存,我们这里就做二级缓存,但这并不代表我的缓存方式不适用于三级缓存。我还会讲如何在三级缓存之后实现二级缓存。

用vue-cli2的脚手架搭建了一个项目,并用这个项目来说明如何实现

让我们先看看项目目录

删除无用组件目录和资产目录,增加src/pages目录和src/store目录。pages page是用来存储页面组件的,store就不多说了,和vuex相关的东西都是存储的。添加server/app.js目录以启动后台服务

1.前提

项目引入vue、vuex、vue-router、axios等vue家族桶引入element-ui,只是为了项目美观。毕竟癌症后期比较懒,不想自己写风格去配置config/index.js中的前端代理

引入快递,启动后台,后端开3003端口,给前端提供美国石油学会(美国石油协会)支持来看看服务端代码server/app.js,非常简单,就是造了30条数据,写了3个接口,几十行文件直接搭建了一个结节服务器,简单粗暴解决数据模拟问题,会模拟的用模拟的也行const express=require(' express ')//const body parser=require(' body-parser ')const app=express()让all list=array。from({ length : 30 },(v,i)=({ id: i,name: '视频I,isCollect: false}))//后台设置允许跨域访问//前后端都是本地本地主机,所以不需要设置克-奥二氏分级量表跨域,如果是部署在服务器上,则需要设置//app.all('* ',function (req,res,next){//RES . header(' Access-Control-Allow-Origin ',' *)//RES . header(' Access-Control-Allow-Headers ',' X-Requested-With ')//RES . header(' Access-Control-Allow-Methods ',' PUT,POST,GET,DELETE,OPTIONS ')//RES . header(' X-power-By ',' 3。2 .1 ')//RES . header(' Content-Type ',' application/JSON;charset=utf-8 ')//next()//})app。使用(快递。JSON())app。使用(快递。URL编码({扩展的: false })//1获取所有的视频列表app.get('/api/getVideoList ',函数(req,RES){让查询=req。查询让当前页面=查询。当前页面让页面大小=查询。页面大小让列表=所有列表。slice((当前页面-1)*页面大小,当前页面*页面大小)RES . JSON({代码: 0 0,data: {列表,合计:全部列表。长度} }))//2获取某一条视频详情app。get('/API/GetVideoDetail/: id ',函数(req,RES){ let id=Number(req。参数。id)让信息=所有列表。find(v=v . id===id)RES . JSON({代码: 0 0,data: info })})//3收藏或者取消收藏视频app.post('/api/collectVideo ',函数(req,RES){ let id=Number(req。尸体。id)let is collect=req。尸体。收集所有列表=所有列表。map((v,i)={ return v.id===id?{.v,IsCollect } :v })RES . JSON({代码: 0 })})const PORT=3003 app。listen(PORT,function () { console.log('app正在侦听端口港口)})2 .路由配置

在路由配置里面把需要缓存的路由的自指的添加保持活力属性,值为没错,这个想必大家都知道,是缓存路由组件的在我们项目里面,需要缓存的路由是页面列表,所以这个路由的自指的的保持活力设置成没错,其他路由正常写,路由文件src/路由器/index.js如下:

从“vue”导入某视频剪辑软件从“vue路由器”导入路由器从“家”导入./page/home "从导入页面列表"./页面/页面列表"从导入页面尾部"./pages/pageADetail "从导入页面b "./page/page b "导入主要来源"./page/main ' vue . use(路由器)导出默认的新路由器({ routes :[{ path : '/',名称: '主',组件: main,redirect: '/home ',子级: [ { path: 'home ',名称: '家庭',组件:“主页”,{ path:“页面列表”,名称3: '页面开始',组件3:状态管理配置

状态管理的store.js里面存储一个名为排除分解者的数组,这个数组用来操作需要做缓存的组件

state.js

const state={ exclude clones :[]}导出默认状态同时在突变。射流研究…里面加入两个方法,addExcludeComponent是往排除分解者里面添加元素的,removeExcludeComponent是往排除分解者数组里面移除元素

注意:这两个方法的第二个参数是数组或者组件名字

突变。射流研究…

常量突变={ addexcludexchanonent(state,excludexchanonent){ let excludexchanonents=state。excludexchanonents if(数组。isarray(excludexchanonent)){ state。excludexchanonents=[.新集合([.排除分解者,exclude knet])]} else { state。排除网=[.新集合([.excludeconnetts,excludeconnett])]} },//excludeconnett可能是组件名字字符串或者数组removeexcludeconnet(state,excludeconnet){ let excludeconnet=state。excludeconnets if(数组。isarray(exclude knet)){ for(让I=0;I excludexconnent . lentii){ let index=exclude clones。find index(v=v===exclude connet[I])if(index-1){ exclude connet。拼接(索引,1)} } else { for(让I=0,len=excludeComponents.length我透镜;I){ if(exclude connet[I]===exclude connet){ exclude connet。拼接(I,1)断裂} } }状态。排除网络=排除网络} }导出默认值发生变化4。点火电极包裹路由器视图

将App.vue的路由器视图用点火电极组件包裹,main.vue的路由也需要这么包裹,这点非常重要,因为页面列表组件是从它们的路由器视图中匹配的

保持活动: exclude=' excludexconets ' som-component/some-component/保持活动这个写法大家应该不会陌生,这也是尤大神官方推荐的缓存方法,排除属性值可以是组件名称字符串(组件选项的名字属性)或者数组,代表不缓存这些组件,所以状态管理里面的addExcludeComponent是代表要缓存组件,addExcludeComponent代表不缓存组件,这里稍微有点绕,请牢记这个规则,这样接下来你就不会被绕进去了。

App.vue

模板div id=' app ' keepalive : exclude=' excludexconets '路由器-视图v-if=' $ route。梅塔。保持活力“/路由器-视图点火电极路由器-视图v-if='!$路线。梅塔。keepalive '/router-view/div/template script导出默认值{ name : ' App ',计算值: { excludexconets(){返回此.$商店。国家。exclude connects } } }/script main。某视频剪辑软件

模板Li v-for=nav中的nav ' :键=' nav。名为“router-link : to=”nav。名称“{ nav。title } }/router-link/Li/ul keep-alive : exclude=' exclude knets ' router-view v-if=' $ route。梅塔。保持活动状态/路由器-视图/保持活动状态路由器-视图v-if='!$路线。梅塔。keepalive '/router-view/div/template script导出默认值{ name : ' main。vue ',data(){ return { nav s : [{ name : ' home ',title: '首页},{ name: ' pageAList ',title: ' pageAList ' },{ name: 'pageB ',title: 'pageB' }] } },methods: { },computed : { excludexconets(){ return this .$商店。国家。excludeconnets } },created () { }}/script接下来的两点设置非常重要

5.一级组件

对于需要缓存的一级路由页面列表,添加两个路由生命周期钩子在路由器之前和beforeRouteLeave

从导入{获取视频列表}./API ' export default { name : ' page a list ',//组件名与组件对应的路由名不需要相同data(){ return { current page : 1,pageSize: 10,total : 0 0,allList: [],list: [] } },methods : { getvideo list(){ let params={ current page 3360 this . current page,pageSize: this。然后(r={ if(r . code===0){ this . list=r . data . list this . total=r . data . total } })},goIntoVideo (item) { this。$ router . push({ name : ' page adetail ',query: {id: item.id}}) },handleCurrentPage(val){ this . currentpage=val this . getvideo list()} },beforrouteenter(to,from,next) { next(vm={ vm。$ store.commit(' removeexcludeconnet ',' pagerist ')next()})},beforroutelave(to,from,next){ let reg=/pageADetail/if(reg . test(to . name)){ this。$ store.commit(' removeexcludeconnet ',' PageArist ')else { this。$ store.commit(' addexcludexconnet ',' PageArist ')} next()},activated(){ this . GetVideoList()},Mounted () {this。getvideo list()} } before route enter,在进入这个组件pageAList之前,先移除excludeComponents之前的当前组件,也就是缓存当前组件,这样任何路由都会跳转到这个组件,这个组件实际上是被缓存的。将触发激活的钩子beforeRouteLeave:离开当前页面。如果跳转到pageADetail,则需要在excludeComponents中移除当前组件pageAList,即缓存当前组件。如果跳转到其他页面,则有必要将pageAList添加到excludeComponents中,也就是说,不缓存当前组件以获取数据的方法在挂载或创建的钩子中调用。如果辅助路由更改数据,并且主路由需要更新,则有必要在激活的钩子中再次获取数据。我们可以收集这个细节并改变列表的状态,所以两个钩子都使用6。次要组件。

将beforeRouteLeave提前路由生命周期挂钩添加到pageADetail,这是需要缓存的主路由的辅助路由组件

在这个beforeRouteLeave钩子中,您需要首先清除第一级组件的缓存状态,然后在跳转路由与第一级组件匹配时缓存第一级组件

Beforerouteleave (to,from,next){让组件名=' '//离开详细信息页面时,将pageAList添加到exludeComponents。也就是说,需要缓存的页面列表设置为未缓存状态,让list=['page a list']这个。$ store . submit(' addexcludeconnet ',List) //缓存从组件路由名称到组件名称的映射。let map=new map([[[' page list ',' page a list']])组件名=map。到达。name)| | ' '//如果离开时要跳转的路由是pageAList,则从exludeComponents中移除pageAList,即缓存page a list这个。$ store . submit(' removeexcludeconnet ',组件名)next ()} 7。实施方法总结

进入页面列表时,它被缓存在beforeRouteEnter中,离开当前组件时有两种情况:

1跳转到页面详细信息,在beforeRouteLeave中缓存页面列表释放页面列表的钩子,从页面详细信息离开时有两种情况

(1)返回到pagerist,然后pagerist被缓存在pagedetail的beforeRouteLeave hook中,那么这就是pagerist-page detail-page一个列表可以被缓存的时候,还是之前的页码状态呢?

(2)输入其他路由,清除页面尾的前一个钩子中的页面列表缓存

2跳转到非页面尾部页面,并清除页面列表的beforeRouteLeave释放钩子中的页面列表缓存

方案评价

我认为这个方案是用来实现缓存的,最终效果是完美的

缺点:

代码很多,缓存代码不容易重用。性能问题:如果激活的钩子写在要缓存的一级组件中,从非一级组件对应的二级组件进入要缓存的一级组件时,接口请求数据会被发送两次,一次在挂载,一次在激活。因此,如果您想追求几行代码来完美地解决缓存问题,您在这里无能为力。

Github地址的项目源代码(本地下载),欢迎克隆和下载

项目启动及效果演示

npm安装安装项目依赖于npm运行服务器来启动后台服务器,以侦听本地3003端口npm运行开发来启动前端项目3级缓存

以上方法,L2缓存,就够了

我们上面讲的是两页的问题,L2缓存。现在假设有三页,A1-A2-A3,一步一步点进去。从A3返回A2时,缓存A2,从A2返回A1时,缓存A1。你可以自己研究,这里就不写了。其实就是上面的想法供大家研究。

摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。

版权声明:vue项目中实现缓存的最佳方案详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。