Open yangkaiyangyi opened 6 years ago
缓存组件keep-alive的使用 一.使用场景 在实际的项目开发中,我们或多或少会遇见一种情况———有些组件我们是没有必要多次进行渲染。例如我们从一个页面A路由跳转到另一个页面B,这时返回页面A时我们需要页面A保持离开前的状态不改变,此时就是keep-alive大展神功的时候了,下面我们一起来看一看keep-alive是如何使用的。 二.keep-alive用法 1.缓存路由 想要完成缓存路由的操作,我们需要以下几步操作 ①.配置路由信息 ②.创建keep-alive标签 ③.通过v-if来判断需要缓存那些路由 <keep-alive> <router-view v-if = "$route.meta.keepAlive"></router-view> </keep-alive> // 除了需要缓存的路由 还要创建一个非缓存路由的入口 <router-view v-if = "!$route.meta.keepAlive"></router-view> //路由配置 routes: [ { path: '/Message', name: 'Message', component: Message, meta: { title: 'xxxxx', keepAlive:true //需要被缓存 } }, { path: '/Midware', name: 'Midware', component: MidwarePage, meta: { keepAlive:false //不需要被缓存 }, } ] 2.缓存组件 keep-alive提供了两个Props: include - 字符串或正则表达式。只有匹配的组件会被缓存。 exclude - 字符串或正则表达式。任何匹配的组件都不会被缓存。 这两个属性可以让我们选择性的来缓存某个组件或者路由,这样为我们的操作提供了灵活性,操作如下: ①.组件注册name ②.创建keep-alive标签 ②.通过include进行缓存 //app.vue <keep-alive :include="componentName"> <router-view ></router-view> </keep-alive> export default { data(){ componentName: ['storeTestA'] } } //storeTestA.vue export default { name:'storeTestA', data(){ } } exclude这里就不赘述了 用法是一样的,但是有一点需要明确,exclude的优先级是大于include的: //这里使用的是逗号分隔字符串,上面例子中使用的是数组形式,还有正则表达式的形式,需要的时候了解下 <keep-alive include="a,b" exclude="a"> //只有a不被缓存 <router-view></router-view> </keep-alive> 3.keep-alive提供的两个周期函数 activated:keep-alive 组件激活时调用 deactivated:keep-alive 组件销毁时调用 三.keep-alive带来的问题 keep-alive进行缓存后,这个组件或者路由的所有都会被缓存住。例如从这个页面A到页面B,此时页面B回到页面A,页面A被缓存是正确的,而后会发现页面C到页面A,发现页面A,页面A还是被缓存住的,此时与我们的业务就有了冲突,这时候哦我们怎么办呢???? 首先我们先了解一些路由钩子: 全局守卫: router.beforeEach 全局前置守卫 进入路由之前 router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用 router.afterEach 全局后置钩子 进入路由之后 使用方法: // main.js 入口文件 import router from './router'; // 引入路由 router.beforeEach((to, from, next) => { next(); }); router.beforeResolve((to, from, next) => { next(); }); router.afterEach((to, from) => { console.log('afterEach 全局后置钩子'); }); to,from,next 这三个参数: to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。 next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。 next() 进入该路由。 next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。 next 跳转新路由,当前的导航被中断,重新开始一个新的导航。 我们可以这样跳转:next('path地址')或者next({path:''})或者next({name:''}) 且允许设置诸如 replace: true、name: 'home' 之类的选项 以及你用在router-link或router.push的对象选项。 路由组件内的守卫: beforeRouteEnter 进入路由前 beforeRouteUpdate (2.2) 路由复用同一个组件时 beforeRouteLeave 离开当前路由时 使用方法: beforeRouteEnter (to, from, next) { // 在路由独享守卫后调用 不!能!获取组件实例 `this`,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 `this` // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用,可以访问组件实例 `this` } 下面重点说一下我们即将使用的beforeRouteEnter访问this问题: 因为钩子在组件还没有创建实力的时候调用,所以无法使用组件实例this。但是可以传一个回调给next来访问组件实例。 至此,我们的问题就完美解决了: beforeRouteEnter (to, from, next) { next(vm => { //清除缓存 通过路径来判断 if (from.path.includes('/请求地址')){ //这个路径来的 则不操作 } else { //这里可以进行一系列的清除操作 vm.tableData = []; vm.form = {}; vm.queryParams = {}; } }); }, 注:触发钩子完整顺序: 将路由导航、keep-alive、和组件生命周期钩子结合起来的,触发顺序,假设是从a组件离开,第一次进入b组件: 1. beforeRouteLeave:路由组件的组件离开路由前钩子,可取消路由离开。 2.beforeEach: 路由全局前置守卫,可用于登录验证、全局路由loading等。 3.beforeEnter: 路由独享守卫 4.beforeRouteEnter: 路由组件的组件进入路由前钩子。 5.beforeResolve:路由全局解析守卫 6.afterEach:路由全局后置钩子 7.beforeCreate:组件生命周期,不能访问this。 8.created:组件生命周期,可以访问this,不能访问dom。 9.beforeMount:组件生命周期 10.deactivated: 离开缓存组件a,或者触发a的beforeDestroy和destroyed组件销毁钩子。 11.mounted:访问/操作dom。 12.activated:进入缓存组件,进入a的嵌套子组件(如果有的话)。 执行beforeRouteEnter回调函数next。