Code前端首页关于Code前端联系我们

Vue Router里keep-alive的include该怎么用?这些细节要注意!

terry 2小时前 阅读数 3 #Vue
文章标签 alive include

做Vue项目时,你是不是遇到过“页面切换后状态丢失”的困扰?比如表单填了一半切走,回来全没了;列表页滚动到半路,切回来又得重新滑…这时候Vue里的keep-alive加上include配置就能解决这类问题,但include到底咋用?有哪些细节得注意?今天就把这块儿掰碎了讲明白~

keep-alive和include是干啥的?

先搞懂基础:keep-alive是Vue的内置组件,作用是缓存组件实例,平常组件切换时,Vue会销毁旧组件、创建新组件,有了keep-alive,被缓存的组件实例不会被销毁,切换回来时直接复用,省得重复渲染,性能和用户体验都能提升。

那include是keep-alive的属性,用来指定“哪些组件”要被缓存,打个比方,keep-alive是个“储物箱”,include就是“储物清单”,只让清单上的组件进箱子,其他组件不缓存。

include的值可以是字符串、数组、正则表达式,但得匹配组件的name选项(组件里export default { name: 'XXX' }里的name),比如你想缓存名叫MyForm的组件,include就写'MyForm';多个组件用逗号分隔,像'MyForm,MyList'

include到底该怎么配置?

配置include得注意“匹配规则”和“组件name”这两点,不然容易踩坑:

(1)字符串形式

适合缓存少数组件,多个组件用英文逗号分隔,比如只缓存表单和列表组件:

<keep-alive include="MyForm,MyList">
  <router-view></router-view>
</keep-alive>

但要注意,这里的字符串必须和组件的name完全一致,大小写、拼写错一个都不行!

(2)数组形式

如果要动态控制缓存的组件(比如根据用户操作增删),用数组更灵活,得用v-bind绑定,把include写成数组:

<keep-alive :include="['MyForm', 'MyList']">
  <router-view></router-view>
</keep-alive>

数组里存的是组件name的字符串,同样要和组件内的name严格匹配。

(3)正则形式

想批量匹配组件(比如所有名字带Form的组件),可以用正则,但必须配合v-bind,因为正则是JS表达式:

<keep-alive :include="/Form$/">
  <router-view></router-view>
</keep-alive>

这里正则/Form$/表示“名字以Form结尾的组件”都会被缓存,比如MyFormOrderForm这些组件。

划重点:组件必须显式写name选项!如果是单文件组件(.vue),没写name的话,Vue会默认取文件名(比如MyForm.vue默认name是MyForm),但如果是匿名组件或者用函数式组件,name可能不对,所以最好手动写name,避免匹配失败。

哪些场景适合用include?

不是所有页面都需要缓存,这些场景用include特别香:

(1)表单类页面

比如用户填收货地址、填个人信息的页面,填了一半切到其他页,回来还能接着填,这时候给表单组件设个name(比如AddressForm),include里加上它,切换时组件实例被缓存,输入框内容、选择器状态都不会丢。

(2)列表 + 详情页

列表页下滑到第10条,点进详情页再返回,列表还能停在第10条位置,给列表组件设name(比如GoodsList),include缓存它,就能保留滚动条位置和已加载的数据。

(3)多步骤流程页

像电商下单的“地址→支付→确认”三步,每一步是个组件,用include缓存这三个组件,用户回退步骤时,之前填的信息(比如地址、支付方式)还在,不用重新选。

举个实际例子:做一个“求职流程”页面,分“填简历→选岗位→确认投递”三步,每个步骤是独立组件,把这三个组件的name放进include数组,用户切换步骤时,每一步的输入内容、选择状态都能保留,体验感拉满~

用include时容易踩的坑,你中过几个?

配置看着简单,实际用的时候容易栽跟头,这些坑得避开:

(1)组件name“对不上”

最常见!比如组件里name写的是'MyForm',include里写成'myform'(小写),或者拼错成'MyFrom',缓存直接失效,解决方法:组件name和include配置逐字对照,别偷懒!

(2)动态修改include不生效

比如想点击按钮,把某个组件加入缓存列表,用数组存name,但修改数组后include没反应,这是因为Vue对数组的“响应式”有要求——直接修改数组索引(比如arr[0] = 'xxx')不会触发更新,得用pushsplice这些方法,或者用计算属性/ watch来维护数组。

举个错误案例:

// 直接改索引,不触发响应式
cachedNames[0] = 'NewComponent' 
// 正确做法:用push或splice
cachedNames.push('NewComponent') 

(3)和Vue Router结合时“搞混name”

路由配置里也有name(比如{ path: '/form', name: 'formRoute' }),但keep-alive的include匹配的是“组件的name”,不是“路由的name”!很多人误以为路由name和组件name是一回事,结果缓存失败,解决方法:路由组件里必须单独写name选项,和路由name没关系,

// 路由组件MyForm.vue里的配置
export default {
  name: 'MyForm', // 这个name给keep-alive匹配用
  // ...其他逻辑
}

(4)缓存后生命周期“变了”

组件被缓存后,createdmounted这些钩子只会在第一次创建时执行,之后切换回来不会再执行,这时候得用activateddeactivated钩子:组件被激活(从缓存中取出复用)时触发activated,被缓存时触发deactivated,如果想每次切换回来都执行逻辑,得把代码放到activated里。

比如表单组件想每次激活时请求最新的下拉选项,就得这么写:

export default {
  name: 'MyForm',
  activated() {
    this.fetchOptions() // 每次激活时请求数据
  },
  methods: {
    fetchOptions() { ... }
  }
}

include和exclude怎么选?

keep-alive还有个属性叫exclude,作用是“排除哪些组件不缓存”,选include还是exclude,看场景:

  • 大部分组件要缓存,只有少数不缓存→用exclude,比如后台管理系统,90%页面需要缓存,只有登录页、404页不需要,就给exclude设这两个组件的name。
  • 大部分组件不缓存,只有少数要缓存→用include,比如官网类项目,只有几个表单页需要缓存,其他页面切换时销毁,就用include指定这几个表单组件。

举个栗子:做一个博客网站,文章列表和文章详情页不需要缓存(每次刷新看最新内容),但“写评论”的弹窗组件(或单独页面)需要缓存用户输入的内容,这时候用include指定评论组件的name,比用exclude排除所有页面更简单。

结合Vue Router的实际案例:多标签页缓存

很多后台系统有“多标签页”功能(比如点击菜单打开多个标签,每个标签对应一个路由),需要缓存用户打开过的标签页,这时候include+Vue Router的组合就能实现:

步骤1:给路由组件加name

每个路由对应的组件(比如PageA.vuePageB.vue)里显式写name:

// PageA.vue
export default {
  name: 'PageA',
  // ...
}

步骤2:维护缓存的组件name数组

在父组件(比如Layout.vue)里,用数组cachedTabs存当前要缓存的组件name,然后绑定给keep-alive的include:

<template>
  <div class="layout">
    <keep-alive :include="cachedTabs">
      <router-view></router-view>
    </keep-alive>
    <div class="tabs">
      <!-- 标签页切换按钮,点击时更新cachedTabs -->
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      cachedTabs: [] // 初始为空
    }
  },
  watch: {
    // 监听路由变化,把当前组件的name加入cachedTabs
    '$route'(to) {
      const componentName = to.matched[0].components.default.name
      if (!this.cachedTabs.includes(componentName)) {
        this.cachedTabs.push(componentName)
      }
    }
  }
}
</script>

步骤3:关闭标签时移除缓存

当用户关闭某个标签页时,从cachedTabs数组里删掉对应的组件name,这样该组件就不再被缓存:

methods: {
  closeTab(tabName) {
    const index = this.cachedTabs.indexOf(tabName)
    if (index > -1) {
      this.cachedTabs.splice(index, 1)
    }
  }
}

这样一来,用户打开的标签页会被缓存,关闭后缓存清除,完美实现多标签页的状态保留~

keep-alive的include是个“精准控制缓存”的利器,但得注意组件name匹配、配置形式、和Vue Router的配合这些细节,下次再碰到“状态丢失”的问题,先想想include怎么用,把组件按需求圈进缓存清单里,用户体验和性能都能UpUp~要是还有疑问,评论区随时聊~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门