keep-alive 實現後退不刷新並保持滾動位置

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>

代碼請參考連接
後退不刷新還能夠經過include實現,可參考連接this

相關文章
相關標籤/搜索