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>