1.keep-alive是什么
keep-alive是Vue提供的一个(抽象)组件
2.作用:
主要用于保留组件状态或避免重新渲染。
3.主要内容
3.1 两个钩子函数
activated:激活,当组件在keep-alive内被切换时,进入组件触发
deactivated:缓存,当组件在keep-alive内被切换时,离开组件触发
3.2 特点
vue官方解释:
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
3.3 注意点:
只能用在只有一个子组件的情况。如果你在其中有 v-for 则不会产生效果。
3.4 keep-alive 常用的几种方式
1. 动态组件
1. <keep-alive> 2. <component :is="view"></component> 3. </keep-alive>
2. 当出现条件判断时的子组件
1. <keep-alive> 2. <comp-a v-if="a > 1"></comp-a> 3. <comp-b v-else></comp-b> 4.
3. 结合路由使用时
1. <keep-alive> 2. <router-view></router-view> 3. </keep-alive>
3.5 两个属性 include 与 exclude
作用:让谁缓存,就让谁缓存
特点:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
具体使用举例:
1. <keep-alive include="a,b"></keep-alive> 2. <keep-alive :include="/a|b/"></keep-alive> 3. <keep-alive :include="['a', 'b']"></keep-alive>
4.工作中的实际使用、应用
举个例子:
手机App中,点击A模块往下滑动,假设滑动到100px,接着又点击B模块,进入B页面,然后我又跳回A页面,A页面的位置依然在100px位置处。
问题来了,假设这个产品经理,非要切回A页面位置要求在每一次进入一个组件时页面的初始位置都是保持在顶部的,何解?
下面给出两个解决方法:
4.1 利用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 } } } })
4.2 利用钩子函数
在keep-alive激活会触发activated钩子函数,那么在该函数内设置scrollTop为0
5.使用的后果及消除不利影响
5.1 问题解释:
被keep-alive包裹的组件我们请求获取的数据不会再重新渲染页面,这也就出现了例如我们使用动态路由做匹配的话页面只会保持第一次请求数据的渲染结果,所以需要我们在特定的情况下强制刷新某些组件
5.2 解决一:利用include、exclude属性
思路:只缓存我们想缓存的,使用时尽量避免
解决二:利用meta属性
export default[ { path:'/', name:'home', components:Home, meta:{ keepAlive:true //需要被缓存的组件 }, { path:'/book', name:'book', components:Book, meta:{ keepAlive:false //不需要被缓存的组件 } ]
<keep-alive> <router-view v-if="this.$route.meat.keepAlive"></router-view> <!--这里是会被缓存的组件--> </keep-alive> <keep-alive v-if="!this.$router.meta.keepAlive"></keep-alive> <!--这里是不会被缓存的组件-->
解决三:官方提出的解决方案响应路由参数的变化
解决四:利用berforeRouteEnter实现前进刷新,后退缓存资料
解决五:利用第三方插件实现前进刷新,后退不缓存
6.vue中强制刷新组件的方法(终极解决)
6.1 v-if
思路:直接从DOM上添加和删除
总结:太简单,太粗暴(但是太省心…),性能要求高的不要用这个
6.2 使用Vue的内置forceUpdate
方法(官方推荐)
使用 this.$forceUpdate();函数在需要的地方刷新
思路:通常情况下,Vue 会通过更新视图来响应依赖项中的更改。然而,当我们调用forceUpdate
时,也可以强制执行更新,即使所有依赖项实际上都没有改变。
注意:这不会更新任何计算属性,调用forceUpdate
仅仅强制重新渲染视图。
代码示例:
// 全局 import Vue from 'vue'; Vue.forceUpdate(); // 使用组件实例 export default { methods: { methodThatForcesUpdate() { // ... this.$forceUpdate(); // ... } } }
6.3 在组件上进行 key 更改(官方推荐)
思路:利用vue的虚拟DOM中diff算法,key值改变,会引起局部刷新进而达到组件刷新的目的。
实现:我们给组件来一个 : key 绑定一个变量,然后可以设置按钮点击事件让key++,从而刷新组件,也可以用watch+时间戳实现,下面贴一个示例代码
watch:{ "key":function(){ this.key=new Date().getTime() } }