vue能够经过<keep-alive>元素包裹组件,实现缓存,下次使用时不须要从新建立该组件。但存在一个问题:keep-alive包裹的组件中有滚动元素时,keep-alive不会储存滚动位置。vue
实现后退不刷新主要依据keep-alive组件的activated和deactivated这两个生命周期钩子函数。git
vue钩子函数的执行顺序:
不使用keep-alive
beforeRouteEnter --> created --> mounted --> destroyedgithub
使用keep-alive
初次进入页面,beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存的页面,只会触发beforeRouteEnter -->activated --> deactivated。created和mounted不会再执行。
其中,
activated在keep-alive组件激活时调用.
deactivated在keep-alive组件被停用时调用.vue-router
Demo实现了后退不刷新,而且返回时滚动到上次浏览的深度。segmentfault
该demo中,包含三个连接导航。缓存
home --> pageA --> pageB --> pageC
依次前进,每次前进到一个新页面都须要获取数据,而按下后退键后,
从pageC返回到pageB,pageB再也不获取新数据,而是使用以前缓存的数据。
从pageB返回到pageA时,pageA再也不获取新数据,而是使用以前的数据。而且当pageA存在滚动条时,返回时会滚动到上次浏览高度。
因此,pageA和pageB须要缓存,pageC不须要缓存。函数
//router.js import Vue from 'vue'; import Router from 'vue-router'; Vue.use(Router); const router = new Router({ mode: 'hash', routes: [ { path: '/', name: 'home', component: () => import('./views/Home.vue'), meta: { title: '首页', keepAlive: false //此组件不须要被缓存 } }, { path: '/pageA', name: 'pageA', component: () => import('./views/pageA.vue'), meta: { title: 'pageA', keepAlive: true, isBack: false } }, { path: '/pageB', name: 'pageB', component: () => import('./views/pageB.vue'), meta: { title: 'pageB', keepAlive: true, isBack: false } }, { path: '/pageC', name: 'pageC', component: () => import('./views/pageC.vue'), meta: { title: 'pageC', keepAlive: false } } ] }); export default router;
//pageA.vue <template> <div class="page-a"> <h1>pageA</h1> <div> <div class="item" v-for="item in items" @click="goPageB"> {{ item }} </div> </div> <h1 @click="goPageB">go pageB</h1> </div> </template> <script> export default { name: 'PageA', data() { return { msg: "我是PageA页面", items: Array.from({length:50}, (v,k) => k), data: "", scrollTop: 0 }; }, beforeRouteEnter(to, from, next) { if(from.name == 'pageB'){ to.meta.isBack = true; } next(); }, mounted() { console.log('mounted....'); // this指向组件的实例,$el指向当前组件的DOM元素 const $el = this.$el; //滚动事件 $el.addEventListener("scroll", () => { //记录位置 this.scrollTop = $el.scrollTop; }); }, activated() { if(!this.$route.meta.isBack){ // 若是isBack是false,代表须要获取新数据,不然就再也不请求,直接使用缓存的数据 this.getData(); } else { //恢复滚动条高度 if(this.scrollTop) { setTimeout(() => { this.$el.scrollTop = this.scrollTop; }, 100); } } // 恢复成默认的false,避免isBack一直是true this.$route.meta.isBack = false; }, methods: { getData() { // getData方法,模拟从后台请求数据 this.data = "数据"; console.log('get data') }, goPageB(){ this.$router.push({ path: "/pageB" }); }, back() { this.$router.push({ path: "/" }); } }, } </script> <style> .page-a { height: 100vh; overflow-y: auto; } .item { margin: 5px; padding: 10px; background: #ccc; } </style>