共计 2555 个字符,预计需要花费 7 分钟才能阅读完成。
前言
本文介绍的是在做微前端 single-spa 我的项目过程中,遇到的 Vue 子利用和 React 子利用相互跳转路由时遇到的问题。
我的项目状况:single-spa 我的项目,基座用的是 React,目前是 2 个子利用一个 Vue 一个 React。路由计划是 Vue Router,React Router + history。
有交互场景是从 Vue 子利用跳转到 React 子利用,或者从 React 子利用跳转到 Vue 子利用,因而遇到了问题。
遇到的问题
联合我的项目诉求和遇到的问题,大家能够先思考一下有什么解决方案~
—————————— 分割线 ——————————
解决的计划
次要是要解决好以下 2 个因素:
- 失常触发以后页面的路由钩子
- 失常传路由参数到目标页面
我一开始尝试去查阅社区文章和看局部源码,看是否有什么非凡形式自主去触发路由钩子,等钩子解决实现之后再跳转去目标页面(跳去 Vue 用 Vue Router,跳去 React 用 React Router)
但看源码下来发现,想要触发 Prompt 还是须要调用 history.push 触发流程,想要触发 Vue Router 导航守卫还是须要调用 VueRouter.push 触发流程
所以联合这两点我整出了解决方案,已应用在我的项目当中,上面是封装的全局路由跳转工具:
window.micro = {
// 子利用,会在相应利用挂载实现后设置
apps: {vue: null, react: null},
history: {push: (location, onComplete, onAbort) => {
const url = typeof location === 'string' ? location : location.path;
// 判断是哪个子利用
const currentIsReact = isReactApp();
const nextIsReact = isReactApp(`#${url}`);
// 解决路由参数
let state = {};
let query = {};
let name = '';
if (typeof location !== 'string') {state = location.params || {};
query = location.query || {};
name = location.name || '';
}
if (!currentIsReact && nextIsReact) {
// vue 跳 react:先用 vue-router 跳,在跳完的回调里再用 history 跳
const reactHistoryHandle = () => {onComplete?.();
history.push(`#/temp?t=${Math.random()}`);
history.replace({state, pathname: url, search: setQueryStringArgs(query) });
// 因为跳多了 1 次 vue-router,所以 back 一下
window.micro.apps.vue2.$router.back();};
window.micro.apps.vue.$router.push(name ? { name, params: state, query} : {path: url, query}, reactHistoryHandle, onAbort);
} else if (currentIsReact && !nextIsReact) {
// react 跳 vue:先用 history 跳长期路由,再用 vue-router 跳,要配合 history.listen 做解决
react2vue = () => {window.micro.apps.vue.$router.push(name ? { name, params: state, query} : {path: url, query}, onComplete, onAbort);
};
history.push('/temp_react_to_vue');
} else if (currentIsReact && nextIsReact) {// react 跳 react:没有非凡,失常用 history 跳} else {// vue 跳 vue:没有非凡,失常用 vue-router 跳}
},
},
};
配合的监听和工具函数:
// 解决 react 跳 vue 的状况
let react2vue = null;
history.listen((location, action) => {
// 解决在长期路由的下一个路由,要返回上一个路由时,须要跳过长期路由
if (location.pathname === '/temp_react_to_vue' && action === 'POP') {history.goBack();
} else if (location.pathname === '/temp_react_to_vue') {
// 在这里跳去实在的 vue-router 路由
react2vue?.();
react2vue = null;
}
});
// 工具函数
function isReactApp(hash = location.hash) {
// 理论依据本人微服务项目的子利用状况判断
return hash === ''|| hash ==='#/'|| ['#/list','#/read/','#/compose','#/login'].some(router => hash.startsWith(router))
;
}
// 把 query 参数变成 query 字符串,如 {a:1, b:2} 返回 ?a=1&b=2
function setQueryStringArgs(args) {
let str = '';
args = args || {};
for (const [key, value] of Object.entries(args)) {str += `${key}=${encodeURIComponent(String(value))}`;
}
return str ? `?${str}` : '';
}
总结
这是我在理论我的项目中应用的计划,如有更优雅更好的计划,心愿在评论区和我探讨~
播种 / 小彩蛋
因为之前曾经对 Vue Router 原理和源码比拟相熟了,所以这次借着这个问题,次要是去理解了 React Router 的 Prompt 组件的实现,这里简略总结一下:
正文完