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 的优雅封装方式!!!
点赞加关注,永远不迷路