背景
Vue 项目被嵌入到 <iframe>
中,通过src加载页面,结果打开后直接访问404,但是如果不是通过iframe打开的话是不会出现这个问题的。
css
<iframe src="/dist/index.html"></iframe>
问题现象
在首次进入时,Vue Router 没有正确地导航到首页路由,而是到了404页面。
原因
由于 iframe 的加载是异步的,Vue Router 在初始化时iframe的url还没准备好。所以要在 iframe 加载完成时,设置正确的路由信息从而导航过去。所以就从iframe加载完后重新设置导航这个关键点下手。
解决方案
方案一:iframe的src的URL 参数中增加初始路由信息
- 在 iframe 的 src 属性中通过url参数添加首页的路由信息,
css
<iframe src="/dist/index.html?route=/dashboard"></iframe>
- 再在 Vue 应用程序初始化时,如果读取到了router则跳转过去。
javascript
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 方案1:根据添加的url参数判断
const routeParam = new URLSearchParams(window.location.search).get('route');
if (routeParam) {
router.push(routeParam);
}
new Vue({
router,
render: h => h(App),
}).$mount('#app')
方案二:使用 postMessage 实现父页面和iframe的通信
- 父页面监听iframe加载完后通过postMessage发送消息:
ini
const iframe = document.getElementById('myIframe');
if (iframe) {
iframe.onload = function() {
iframe.contentWindow.postMessage({ route: '/dashboard' }, '*');
};
}
- iframe内页面main.ts中监听消息,设置路由
csharp
// 方案2:postMessage来实现iframe的通信
window.addEventListener('message', handleMessage, false);
function handleMessage(event: any) {
const { data } = event;
if (data.route) {
console.log('message', event, data.route);
router.push(data.route); // 导航到接收到的路由
}
}
方案三:利用路由钩子
利用 Vue Router 的导航守卫,在路由导航前检查 URL 参数中是否存在初始路由信息,如果存在则进行相应的导航处
scss
// 方案3: 路由拦截
router.beforeEach((to, from, next) => {
if (to.matched.length === 0) {
// 如果未匹配到任何路由,说明当前页面可能是初始加载
next('/dashboard/base'); // 或者重定向到默认页面
} else {
next(); // 继续正常导航
}
});
结果
先把今天遇到的问题简单总结下,虽然用方案1解决了,试了下方案2、3都有问题,需要调试,也没调出来,但感觉思路应该是没错的吧。
标题 | 优点 | 缺点 | 问题 |
---|---|---|---|
方案一 | 简单,直接,只需要在内嵌的项目写代码 | url结构不好看 | 最终使用 |
方案二 | 不需要修改url | 需要内嵌iframe的页面和iframe的项目中添加额外代码 | 通信有问题,还没调试出来。。。 |
方案三 | 不需要修改url | 路由钩子每个都处理了 | 逻辑有问题 |