vue页面实现前进刷新,后退不刷新

背景

业务需求,实现跳转进页面的时候重新加载页面,后退的时候保持缓存。搜索了很多的回答,大概有几种方法:
1、keepalive判断router-view --> 缓存不生效。
2、includes --> 无法实现前进刷新
3、页面里做路由监听 --> 没有测试,太过于繁琐

方案

1、重写router的push和replace方法,记录路由的历史
2、跳转的方法里加入t参数,清除路由缓存,实现刷新
3、跳转回已有路由时,清除后面的记录,不会无限返回; exp a -> b -> c -> d, d跳转到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));
});

// 监听返回事件
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方法,统一处理跳转和错误捕获
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方法,统一处理跳转和错误捕获
    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版本的代码在某些情况下会出现错误,而且定时器跳转在体验上不太友好,因此我在这段代码的基础上做了一些修改,目前测试下来没有问题,完整的代码如下

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方法,统一处理跳转和错误捕获
  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

后续如果有问题继续更新。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容