了解之前你先从动态组件说起~
component
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:
上述内容可以通过 Vue 的 <component>
元素加一个特殊的 is attribute 来实现:
<template>
<div class="hello">
<button @click="handleAbout">About</button>
<button @click="handleHome">Home</button>
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
</div>
</template>
<script>
import About from "./about";
import Home from "./home";
export default {
name: "HelloWorld",
components: {
About,
Home
},
props: {
msg: String
},
data() {
return {
currentTab: 'About'
};
},
methods: {
handleAbout () {
this.currentTab = 'About'
},
handleHome () {
this.currentTab = 'Home'
}
}
};
</script>
component默认每次都会销毁和重建,那么为了性能优化,我们可以使用keep-alive缓存,缓存还有一些其他的作用,比如切换时保留滚动位置,切换时保留页面输入的内容,等等等
keep-alive
将keep-alive包裹你的component
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
这样就可以保留tab之间用户的输入的信息了,但是并不能保留滚动的位置,不信你看下面代码,一个tab里面不需要滚动,而另外一个tab需要滚动。
about.vue
<template>
<div>
about
</div>
</template>
<script>
export default {
}
</script>
<style lang="">
</style>
home.vue
<template>
<div class="wrapper">
<ul>
<li v-for="(item, index) in 50" :key="index">
{{item}}
</li>
</ul>
</div>
</template>
<script>
export default {
}
</script>
<style>
.wrapper {
height: 200px;
overflow: auto;
}
</style>
写法上没啥问题,但就是每次切换的时候不能保留滚动位置,怎么办???
记录滚动位置
解决办法
不使用component和keep-alive组件,使用v-show代替
<home v-show="currentTab==='Home'"></home>
<about v-show="currentTab==='About'"></about>
这里有个需要注意的地方就是,需要把滚动设置到组件里面去,而不是他们共同的父元素,因为他们不能共用滚动,共用滚动的话滚动位置又乱了,所以不要为了偷懒而设置在在父元素中,比如下面代码:
<div class="container">
<home v-show="currentTab==='Home'"></home>
<about v-show="currentTab==='About'"></about>
</div>
.container {
height: 200px;
overflow: auto;
}
其实很多人认为keep-alive能保留滚动位置,也许是你在配合vue-router的时候这样使用过,看下面代码
<keep-alive>
<router-view></router-view>
</keep-alive>
其实keep-alive只能通过点击浏览器自带的返回按钮才能记录位置,如果你需要在A切换到B再切换到A,通过JS的路由跳转是不能记录位置的。来个图片吧,这样直观一点:
通常我们有这样的需求,商品列表跳转的商品详情页,然后返回到商品列表,这个时候是要保留滚动位置的,既然Keep-alive做不到,我们可以使用其他方法。
通过在页面中记录滚动位置,当组件再次被激活时,重新设置一下页面的滚动,代码如下:
export default {
// 1.绑定滚动事件
mounted () {
window.addEventListener('scroll', this.handleScroll)
},
// 3.当再次进入(前进或者后退)时,只触发activated(注:只有在keep-alive加载时调用)
activated () {
if (this.scroll > 0) {
this.$nextTick(() => {
document.documentElement.scrollTop = this.scroll
window.addEventListener('scroll', this.handleScroll)
})
}
},
// 4.deactivated 页面退出时关闭事件 防止其他页面出现问题
deactivated () {
window.removeEventListener('scroll', this.handleScroll)
},
methods: {
// 2.滚动时候保留位置
handleScroll () {
this.scroll = document.documentElement.scrollTop
}
}
};
</script>
有时候我们的页面需要keep-alive保留状态,有些时候我们的页面不需要keep-alive保留状态,这个时候可以使用属性include和exclude属性处理。
include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
更多内容请参考官方文档:链接
总结
- keep-alive可以保留页面的状态,比如表单输入
- keep-alive可以保留触发返回键的滚动位置
- keep-alive不能保留动态组件的滚动位置,需要使用v-show代替
- keep-alive不能保留通过路由切换页面时候的滚动位置,需要在页面组件中单独处理
- keep-alive可以通过exclude排除不需要保留状态的页面
- 使用了keep-alive才会触发的生命周期是activated 和 deactivated