@truenewx/tnxvue3
Version:
互联网技术解决方案:Vue3扩展支持
172 lines (155 loc) • 5.83 kB
JavaScript
/**
* 基于Vue的路由器构建函数
*/
import {FunctionUtil, NetUtil} from '@truenewx/tnxcore/src/tnxcore-util';
function addRoute(routes, superiorPath, item, fnImportPage) {
if (item && item.path) {
let page = item.page || item.path.replace(/\/:[a-zA-Z0-9_]+/g, '');
let route = {
path: item.path,
meta: {
superiorPath: superiorPath,
page: page,
cache: {}, // 路由级缓存
isHistory() { // 通过setTimeout()方式调用才能确保获得正确结果
return this.historyFrom !== undefined;
},
},
component: item.component,
};
if (!route.component) {
route.component = () => {
return fnImportPage(page);
};
}
// 如果直接定义route的redirect/alias字段,则item的redirect/alias为undefined时,route仍然有redirect/alias字段,只是其值为undefined,这将导致VueRouter报错
if (item.redirect) {
route.redirect = item.redirect;
}
if (item.alias) {
route.alias = item.alias;
}
routes.push(route);
}
}
function applyItemsToRoutes(superiorPath, items, routes, fnImportPage) {
if (items && items.length) {
items.forEach(item => {
if (item) {
addRoute(routes, superiorPath, item, fnImportPage);
applyItemsToRoutes(item.path, item.subs, routes, fnImportPage);
}
});
}
}
function instantiatePath(path, params) {
if (path && path.contains('/:')) {
if (params) {
Object.keys(params).forEach(key => {
path = path.replace('/:' + key + '/', '/' + params[key] + '/');
});
}
if (path.contains('/:')) { // 参数替换完之后,还有路径参数,则为无效路径,返回首页
console.warn(
'路径中的参数无法获得参数值,请确保具有参数的路径所属菜单项的下级菜单路径包含相同的参数:' + path);
return '/';
}
}
return path;
}
function getCurrentRoute(router) {
return router.currentRoute._value;
}
export default function (VueRouter, menu, fnImportPage) {
let items;
if (Array.isArray(menu)) {
items = [];
menu.forEach(function (m) {
if (Array.isArray(m.items)) {
items = items.concat(m.items);
} else { // menu实际上是items
items.push(m);
}
});
} else {
items = menu.items;
}
const routes = [];
applyItemsToRoutes(undefined, items, routes, fnImportPage);
const routerHistory = VueRouter.createHistory();
const router = VueRouter.createRouter({
history: routerHistory,
routes,
});
router.history = routerHistory;
// 浏览器的返回事件触发位于VueRouter的钩子执行和页面渲染之后,这意味着$route.meta.historyFrom必须在页面渲染完之后才具有正确的值
// if (window.history && window.history.pushState) {
// window.history.pushState(null, null, document.URL);
// }
window.addEventListener('popstate', function () {
let $route = getCurrentRoute(router);
if ($route) {
$route.meta.historyFrom = router.history.state.forward;
}
}, false);
// 注册离开页面前事件处理支持
router.$beforeLeaveHandlers = {};
router.beforeLeave = function (handler) {
if (typeof handler === 'function') {
let $route = getCurrentRoute(router);
let path = $route.path;
router.$beforeLeaveHandlers[path] = handler;
}
};
router.beforeEach(function (to, from, next) {
if (typeof window.tnx.router.beforeLeave === 'function') {
window.tnx.router.beforeLeave(router, from);
}
let allow = true;
let beforeLeaveHandler = router.$beforeLeaveHandlers[from.path];
if (beforeLeaveHandler) {
if (beforeLeaveHandler(to) === false) {
allow = false;
}
}
if (allow) {
next();
}
});
router.afterEach(function (to, from) {
router.prev = from;
// 前后路径相同,但全路径不同(意味着参数不同),则需要刷新页面,否则页面不会刷新
if (to.path === from.path && to.fullPath !== from.fullPath) {
window.location.reload();
}
});
router.back = FunctionUtil.around(router.back, function (back, path) {
if (!router.prev || !router.prev.href) { // 没有href,说明当前页面为刷新后进入的第一个页面,无法简单返回
let $route = getCurrentRoute(router);
if (!path) { // 未指定默认返回路径,则返回上一级页面
path = $route.meta.superiorPath;
}
path = instantiatePath(path, $route.params);
if (path) {
router.replace(path);
return;
}
}
back.call(router);
});
router.pushState = function (path) {
let success = NetUtil.pushState('#' + path);
if (!success) {
this.push(path);
}
return success;
};
router.replaceState = function (path) {
let success = NetUtil.replaceState('#' + path);
if (!success) {
this.replace(path);
}
return success;
};
return router;
}