Vue router 的 keep-alive

53 min read

作用

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

使用

包裹需要缓存的Vue组件

<keep-alive>
  <SomeComponent>
  </SomeComponent>
</keep-alive>

props

  • include - 字符串或正则表达,只有匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
<keep-alive include="a">
</keep-alive>

注意: a 为定义的Vue组件属性name的名称

router-view

所有路径匹配到的视图组件都会被缓存

<keep-alive>
    <router-view>
    </router-view>
</keep-alive>

通过meta来设置路由是否缓存

// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]

配置keep-alive

<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件比如 Home -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件比如 Edit -->
</router-view>

非单页应用的时候,keep-alive 并不能有效的缓存

router.meta 拓展

假设这里有 3 个路由: A、B、C。

  • 需求:
    • 默认显示 A
    • B 跳到 A,A 不刷新
    • C 跳到 A,A 刷新
  • 实现方式
    • 在 A 路由里面设置 meta 属性:
{
        path: '/',
        name: 'A',
        component: A,
        meta: {
            keepAlive: true // 需要被缓存
        }
}
  • 在 B 组件里面设置 beforeRouteLeave
export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
             // 设置下一个路由的 meta
            to.meta.keepAlive = true;  // 让 A 缓存,即不刷新
            next();
        }
};
  • 在 C 组件里面设置 beforeRouteLeave
export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
            // 设置下一个路由的 meta
            to.meta.keepAlive = false; // 让 A 不缓存,即刷新
            next();
        }
};

vue实现前进刷新,后退不刷新

使用压栈方式的代码,适用于没有tab界面的时候

大致思路: 创建一个空数组作为堆栈, 判断当前要访问的路由是在前进还是在后退:当前栈中是否为空并且当前路由不在栈的最顶层

let routerList = []
router.beforeEach((to, from, next) => {
    if (routerList.length && routerList.indexOf(to.name) === routerList.length - 1) {
      // 后退
      routerList.splice(routerList.length - 1, 1)
      to.meta.isBack = true
    } else {
      // 前进
      routerList.push(from.name || '/')
      to.meta.isBack = false
    }
    next()
})

使用路由守护判断前进和后退动态修改keep-alive缓存对象

router.beforeEach((to, from, next) => {
  if (to.meta.isBack) {
    console.log('后退。。。')
    to.meta.keepAlive = true
  }
  next()
})

路由守卫的next() 放行到下一路由