2019-09-04 Vue / keep-alive

keep-alive

keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个抽象组件,所以在v页面渲染完毕后不会被渲染成一个DOM元素


    


当组件在keep-alive内被切换时组件的activated、deactivated这两个生命周期钩子函数会被执行

被包裹在keep-alive中的组件的状态将会被保留,例如我们将某个列表类组件内容滑动到第100条位置,那么我们在切换到一个组件后再次切换回到该组件,该组件的位置状态依旧会保持在第100条列表处

image

关于这一点也是仁者见仁,有的产品可能会要求在每一次进入一个组件时页面的初始位置都是保持在顶部的,这里可以利用Vue中的滚动行为,但是前提是你是HTML5 history模式
我们在创建一个router实例的时候,可以提供一个scrollBehavior方法,该方法会在用户切换路由时触发

const router=new VueRouter({
        routes:[
            {
                path:"/",
                component:Home
            }
        ],
        scrollBehavior(to,form,savedPosition){
        //scrollBehavior方法接收to,form路由对象
        //第三个参数savedPosition当且仅当在浏览器前进后退按钮触发时才可用
        //该方法会返回滚动位置的对象信息,如果返回false,或者是一个空的对象,那么不会发生滚动
        //我们可以在该方法中设置返回值来指定页面的滚动位置,例如:
         return {x:0,y:0}
        //表示在用户切换路由时让是所有页面都返回到顶部位置
        //如果返回savedPosition,那么在点击后退按钮时就会表现的像原生浏览器一样,返回的页面会滚动过到之前按钮点击跳转的位置,大概写法如下:
         if(savedPosition){
            return savedPosition
         }else{
           return {x:0,y:0}
         }
         //如果想要模拟滚动到锚点的行为:
         if(to.hash){
           return {
             selector:to.hash
           }
         }
     }
})

还有一个方法就是利用我们上面说过的,在keep-alive激活会触发activated钩子函数,那么在该函数内设置scrollTop为0

被keep-alive包裹的动态组件或router-view会缓存不活动的实例,再次被调用这些被缓存的实例会被再次复用,对于我们的某些不是需要实时更新的页面来说大大减少了性能上的消耗,不需要再次发送HTTP请求,但是同样也存在一个问题就是被keep-alive包裹的组件我们请求获取的数据不会再重新渲染页面,这也就出现了例如我们使用动态路由做匹配的话页面只会保持第一次请求数据的渲染结果,所以需要我们在特定的情况下强制刷新某些组件

  1. 利用include、exclude属性

    
          
    
    
          
    
    
    

    include属性表示只有name属性为bookLists,bookLists的组件会被缓存,(注意是组件的名字,不是路由的名字)其它组件不会被缓存exclude属性表示除了name属性为indexLists的组件不会被缓存,其它组件都会被缓存

  2. 利用meta属性

    export default[
     {
      path:'/',
      name:'home',
      components:Home,
      meta:{
        keepAlive:true //需要被缓存的组件
     },
     {
      path:'/book',
      name:'book',
      components:Book,
      meta:{
         keepAlive:false //不需要被缓存的组件
     } 
    ]
    
    
    
      
      
    
    
    
    
    

这样设置了之后,book页的状态就会保存,返回键返回到book时页面不会重新渲染了。

但是有问题啊!!!从book列表页跳到任何页面,再返回book列表页都不会刷新页面!这并不是我想要的,我只要从home主页返回book列表页时不刷新页面,其他情况下是需要刷新的。

所以还需要加一些处理,思路就是从book列表页跳转到其他页面时把book列表页的keepAlive值设置为false,从home主页返回book列表页时把book列表页的keepAlive值设置为true就好了,代码如下:

book跳转到其他页面时把book的keepAlive值设置为false

在book列表页加上如下代码:

beforeRouteEnter(to, from, next) {
   if(from.name=='book'){
      to.meta.isBack=true;
   }
   next();
},
activated() {
   if(this.$route.meta.isBack){
     // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
    doSomeThing...
   }

    // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
    this.$route.meta.isBack=false
},

钩子函数的执行顺序

不使用keep-alive

beforeRouteEnter --> created --> mounted --> destroyed

使用keep-alive

beforeRouteEnter --> created --> mounted --> activated --> deactivated

再次进入缓存的页面,只会触发beforeRouteEnter -->activated --> deactivated 。created和mounted不会再执行。我们可以利用不同的钩子函数,做不同的事。务必理解上述钩子函数的执行时机和执行顺序。

activated和deactivated是使用keep-alive后,vue中比较重要的两个钩子函数,建议详细了解下。

  1. 官方提出的解决方案响应路由参数的变化

  2. 利用berforeRouteEnter实现前进刷新,后退缓存资料

  3. 利用第三方插件实现前进刷新,后退不缓存

  4. vue中 给router-view 组件的 绑定 key 的原因

你可能感兴趣的:(2019-09-04 Vue / keep-alive)