vue頁面實現(xiàn)前進刷新膜毁,后退不刷新

背景

業(yè)務(wù)需求,實現(xiàn)跳轉(zhuǎn)進頁面的時候重新加載頁面愤钾,后退的時候保持緩存瘟滨。搜索了很多的回答,大概有幾種方法:
1能颁、keepalive判斷router-view --> 緩存不生效杂瘸。
2、includes --> 無法實現(xiàn)前進刷新
3伙菊、頁面里做路由監(jiān)聽 --> 沒有測試败玉,太過于繁瑣

方案

1敌土、重寫router的push和replace方法,記錄路由的歷史
2运翼、跳轉(zhuǎn)的方法里加入t參數(shù)返干,清除路由緩存,實現(xiàn)刷新
3血淌、跳轉(zhuǎn)回已有路由時矩欠,清除后面的記錄,不會無限返回悠夯; exp a -> b -> c -> d, d跳轉(zhuǎn)到b時癌淮,再返回時回到a

// App.vue
<keep-alive>
    <router-view ref="routerView" :key="$route.fullPath"></router-view>
</keep-alive>


// router/index.js
Vue.use(VueRouter);
let historyList = [];
let checkFlag = false; // 判斷路由記錄返回標識
let previousPath = ''; // 前一個路由  用于返回后重定向
let targetPath = ''; //

router.afterEach(to => {
    if (!historyList.includes(to.path) && !to.query.replace) historyList.push(to.path);

    if (to.fullPath === previousPath) {
        router.push(targetPath);

        previousPath = '';
        targetPath = '';
    }

    console.log('route each histroy--', JSON.stringify(historyList));
});

// 監(jiān)聽返回事件
window.addEventListener('popstate', () => {
    console.log('popstate begin', checkFlag);
    !checkFlag && historyList.pop();
    checkFlag = false;
    console.log('popstate end', JSON.stringify(historyList));
});


function checkRoute(location) {
    const index = historyList.findIndex(path => path === location.path);
    if (index !== -1) {
        console.log('index--', index);
        const backLen = index - historyList.length;
        previousPath = historyList[index - 1];
        historyList = historyList.slice(0, index);
        checkFlag = true;
        router.go(backLen);
        console.log('1234 route back ---- backlength==', backLen);
    return false;
    }
    return true;
}

const originalPush = VueRouter.prototype.push;
const originalReplace = VueRouter.prototype.replace;
// 重寫原型上的push和replace方法,統(tǒng)一處理跳轉(zhuǎn)和錯誤捕獲
VueRouter.prototype.push = function (target) {
    let location = target;
    if (typeof target === 'string') {
        const path = target.split('?')[0];
        const query = parseQuery(target.split('?')?.[1] ?? '');
        location = { path, query };
    }

    const result = checkRoute(location);

    if (result) {
        location.query = Object.assign({}, location.query, {
            t: new Date().getTime()
        });

        console.log('push begain');

        return originalPush.call(this, location).catch(err => console.log(err));
    }
};

VueRouter.prototype.replace = function (target) {
    let location = target;
    if (typeof target === 'string') {
        const path = target.split('?')[0];
        const query = parseQuery(target.split('?')?.[1] ?? '');
        location = { path, query };
    }

    const result = checkRoute(location);

    if (result) {
        location.query = Object.assign({}, location.query, {
            t: new Date().getTime(),
            replace: true
        });

        console.log('push begain');

        return originalReplace.call(this, location).catch(err => console.log(err));
    }
};

2023/2/21更新

v3版本有所不同沦补,代碼如下

// APP.vue
<template lang="pug">
div
    router-view(v-slot='{ Component }')
        keep-alive
            component(:is='Component', :key='route.fullPath')
</template>

<script lang="ts">
    import { defineComponent } from 'vue';
    import { useRoute } from 'vue-router';

    export default defineComponent({
        setup() {
            const route = useRoute();

            return {
                route
            };
        }
    });
</script>

// 路由router.ts
import { Router, RouteLocationNormalized, parseQuery } from 'vue-router';

export default function intercept(router: Router) {
    let historyList: Array<string> = [];
    let routeReplace = false; // replace方法不添加歷史
    let checkFlag = false; // 判斷路由記錄返回標識

    router.afterEach((to: RouteLocationNormalized) => {
        window.scrollTo(0, 0);
        document.title = String(to.meta?.title);

        if (!historyList.includes(to.path) && routeReplace === false) historyList.push(to.path);

        console.log('after each routerHistory===', JSON.parse(JSON.stringify(historyList)));
    });

    window.addEventListener('popstate', () => {
        console.log('window popstate begain', window.history, historyList.length);

        !checkFlag && historyList.pop();

        checkFlag = false;

        console.log('widow popstate routerHistory===', JSON.parse(JSON.stringify(historyList)));
    });

    function checkRoute(location: any) {
        const index = historyList.findIndex(path => path === location.path);
        console.log('index===', index);

        if (index !== -1) {
            const backLen = index + 1 - historyList.length;
            historyList = historyList.slice(0, index);
            console.log('histroy lsit', JSON.parse(JSON.stringify(historyList)));
            checkFlag = true;
            router.go(backLen);
        }
    }

    const originalPush = router.push;
    const originalReplace = router.replace;
    // 重寫原型上的push和replace方法该默,統(tǒng)一處理跳轉(zhuǎn)和錯誤捕獲
    router.push = function push(target: any) {
        let location: any = target;
        if (typeof target === 'string') {
            console.log(target.split('?'));

            const path = target.split('?')[0];
            const query = parseQuery(target.split('?')?.[1] ?? '');
            location = { path, query };
        }

        console.log('push location----', location);
        routeReplace = false;
        checkRoute(location);

        location.query = Object.assign({}, location.query, {
            t: new Date().getTime()
        });
        return originalPush.call(this, location).catch(err => console.log(err));
    };

    router.replace = function replace(target: any) {
        let location: any = target;
        if (typeof target === 'string') {
            const path = target.split('?')[0];
            const query = parseQuery(target.split('?')?.[1] ?? '');
            location = { path, query };
        }

        console.log('replace location----', location);
        routeReplace = true;
        checkRoute(location);

        location.query = Object.assign({}, location.query, {
            t: new Date().getTime()
        });

        return originalReplace.call(this, location).catch(err => console.log(err));
    };

    return router;
}

2023/7/28更新
上述v3版本的代碼在某些情況下會出現(xiàn)錯誤,而且定時器跳轉(zhuǎn)在體驗上不太友好策彤,因此我在這段代碼的基礎(chǔ)上做了一些修改栓袖,目前測試下來沒有問題,完整的代碼如下

export default function intercept(router: Router) {
let historyList: Array<string> = [];
  let checkFlag = false; // 判斷路由記錄返回標識

  router.beforeEach(
    (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized,
      next: NavigationGuardNext
    ) => {
      if (checkFlag) {
        checkFlag = false;

        next({
          ...to,
          replace: true,
          query: { ...to.query, t: new Date().getTime() },
        });
      } else {
        next();
      }
    }
  );

  router.afterEach(
    (to: RouteLocationNormalized, from: RouteLocationNormalized) => {
      window.scrollTo(0, 0);
      document.title = String(to.meta?.title);

      traceViewManual();

      if (!historyList.includes(to.path) && !to.query.replace)
        historyList.push(to.path);

      if (
        from.path === historyList[historyList.length - 1] &&
        to.path === historyList[historyList.length - 2]
      ) {
        historyList.pop();
      }

      console.log(
        'after each routerHistory===',
        JSON.parse(JSON.stringify(historyList))
      );
    }
  );

  window.addEventListener('popstate', () => { });

  function checkRoute(location: any) {
    const index = historyList.findIndex((path) => path === location.path);

    // tab頁不處理
    if (index !== -1) {
      const backLen = index - (historyList.length - 1);
      historyList = historyList.slice(0, index + 1);
      checkFlag = true;
      router.go(backLen);
      return false;
    }

    return true;
  }

  const originalPush = router.push;
  const originalReplace = router.replace;
  // 重寫原型上的push和replace方法店诗,統(tǒng)一處理跳轉(zhuǎn)和錯誤捕獲
  router.push = function push(target: any) {
    let location: any = target;
    if (typeof target === 'string') {
      const path = target.split('?')[0];
      const query = parseQuery(target.split('?')?.[1] ?? '');
      location = { path, query };
    }

    const result = checkRoute(location);

    if (result) {
      location.query = { ...location.query, t: new Date().getTime() };

      return originalPush
        .call(this, location)
        .catch((err: any) => console.log(err));
    }
    return Promise.resolve(undefined);
  };

  router.replace = function replace(target: any) {
    let location: any = target;
    if (typeof target === 'string') {
      const path = target.split('?')[0];
      const query = parseQuery(target.split('?')?.[1] ?? '');
      location = { path, query };
    }

    const result = checkRoute(location);

    if (result) {
      location.query = {
        ...location.query,
        t: new Date().getTime(),
        replace: true,
      };

      console.log('replace begain');

      return originalReplace
        .call(this, location)
        .catch((err: any) => console.log(err));
    }
    return Promise.resolve(undefined);
  };

  return router;
}

TIP

后續(xù)如果有問題繼續(xù)更新裹刮。。庞瘸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捧弃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子擦囊,更是在濱河造成了極大的恐慌违霞,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞬场,死亡現(xiàn)場離奇詭異买鸽,居然都是意外死亡,警方通過查閱死者的電腦和手機贯被,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門眼五,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人彤灶,你說我怎么就攤上這事看幼。” “怎么了幌陕?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵诵姜,是天一觀的道長。 經(jīng)常有香客問我搏熄,道長棚唆,這世上最難降的妖魔是什么暇赤? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮瑟俭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘契邀。我一直安慰自己摆寄,他們只是感情好,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布坯门。 她就那樣靜靜地躺著微饥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪古戴。 梳的紋絲不亂的頭發(fā)上欠橘,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音现恼,去河邊找鬼肃续。 笑死,一個胖子當著我的面吹牛叉袍,可吹牛的內(nèi)容都是我干的始锚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喳逛,長吁一口氣:“原來是場噩夢啊……” “哼瞧捌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起润文,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤姐呐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后典蝌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曙砂,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年骏掀,在試婚紗的時候發(fā)現(xiàn)自己被綠了麦轰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡砖织,死狀恐怖款侵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侧纯,我是刑警寧澤新锈,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站眶熬,受9級特大地震影響妹笆,放射性物質(zhì)發(fā)生泄漏块请。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一拳缠、第九天 我趴在偏房一處隱蔽的房頂上張望墩新。 院中可真熱鬧,春花似錦窟坐、人聲如沸海渊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臣疑。三九已至,卻和暖如春徙菠,著一層夾襖步出監(jiān)牢的瞬間讯沈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工婿奔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缺狠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓萍摊,卻偏偏與公主長得像儒老,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子记餐,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容