vue2+ts优雅封装vue-router工具

2022-06-04  本文已影响0人  硅谷干货

新建index.ts文件

import Vue from "vue";
import VueRouter from "vue-router";
import { routes } from "./routers";
import RouterMaster from "./RouterMaster";

Vue.use(VueRouter);

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;

export const routerMaster = new RouterMaster(router);

新建routers.ts文件

import { RouteConfig } from "vue-router";

export const routes: Array<RouteConfig> = [
  {
    path: "/",
    name: "home",
    component: () => import("../views/home/index.vue"),
  },
  {
    path: "/order",
    name: "order",
    component: () => import("../views/order/index.vue"),
  },
  {
    path: "/mine",
    name: "mine",
    component: () => import("../views/user/index.vue"),
  },
];

新建RouterMaster.ts文件

import VueRouter, { Route, RawLocation } from "vue-router";
import router from ".";
import findLastIndex from "lodash-es/findLastIndex";
import findIndex from "lodash-es/findIndex";

class RouterMaster {
  history: Array<Route | any> = [];
  constructor(public router: VueRouter) {
    // 重写replace方法, replace之前先pop, 再在afterEach中push
    const rawReplace = router.replace;
    router.replace = (params: RawLocation) => {
      if (this.history.length > 0) {
        this.history.pop();
      }
      return rawReplace(params);
    };
    // 监听浏览器回退, afterEach执行优先于popstate, 所以在此pop 2个长度
    window.addEventListener("popstate", () => {
      const pop = this.history.splice(this.history.length - 2, 2);
    });
    // push\replace\back都会触发afterEach, 在此统一push, 再在响应监听中pop掉
    router.beforeEach((to, from, next) => {
      // 如果未匹配到路由
      if (to.matched.length === 0) {
        //如果上级也未匹配到路由则跳转主页面,如果上级能匹配到则转上级路由
        from.path ? next({ path: from.path }) : next("/");
      } else {
        next();
      }
    });
    router.afterEach((to, from) => {
      this.history.push(to);
    });
  }
  backTo(options: {
    name?: string;
    path?: string;
    index?: number;
    isToFisrt?: boolean;
  }) {
    let key: string, value: string, index: number;
    if (options.index !== undefined) {
      index = options.index;
    } else {
      if (options.name) {
        key = "name";
        value = options.name;
      } else if (options.path) {
        key = "path";
        value = options.path;
      } else {
        throw new Error("Please provide either `name`, `path` or `index`");
      }
      if (options.isToFisrt) {
        index = findIndex(this.history, (route) => route[key] === value);
      } else {
        index = findLastIndex(this.history, (route) => route[key] === value);
      }
    }

    const length = this.history.length;
    let backSteps;
    if (index >= 0) {
      this.history.splice(index + 2, length - index - 2);
      backSteps = length - index - 1;
      router.go(-backSteps);
    } else {
      this.history = [];
      backSteps = length - 1;
      backSteps > 0 && router.go(-backSteps); // 清空路由回退记录
      setTimeout(() => {
        // 等到路由回退完成之后才能replace
        router.replace({
          [key]: value,
        });
      }, 100);
    }
  }
  back() {
    let currentRoute,
      step = 1;
    do {
      currentRoute = this.history[this.history.length - step];
      ++step;
    } while (
      this.history[this.history.length - step].name === currentRoute.name
    );

    this.router.go(-step + 1);
  }
  getCurrentRouteIndex() {
    return this.history.length - 1;
  }
}

export default RouterMaster;

快速集成

直接拷贝到项目中如下:


image.png

这样封装,相比较普通引入方式,定制化程度会很高也更优雅,大家如果不同意见,欢迎交流!!!

众所周知,vue-router路由组件到了vue3中的api发生的巨大变化,下期我会更新vue3 + ts 的优雅封装方式!!!

点赞加关注,永远不迷路

上一篇 下一篇

猜你喜欢

热点阅读