记录一些自己在工作中遇到的问题和解决方法。
问题
vue项目中使用iframe引入了一个3d地图html页面,要求不要每次打开这个页面都重新加载。 项目框架本身设置了切换路由时会使用keep-alive缓存页面,但对iframe页面没有效果。
原因
iframe页里的内容是一个独立的文件,并不属于vue页面结点的信息。iframe结点每一次渲染就相当于打开一个新的网页窗口,所以即使把结点保存下来,在渲染时iframe页还是刷新的。
处理
参考网上的解决方案,最终决定通过以下方法处理: 初始就加载iframe结点,在切换时利用v-show来控制显示隐藏,使iframe的节点不被删除,以此来防止界面节点被重新更新。
具体实现
- 路由设置时,属性component改为iframeComponent,懒加载组件;
{
path: '',
component: Layout,
hidden: true,
redirect: 'noredirect',
children: [
{
path: 'map',
// component: resolve => require(['@/views/map/index.vue'], resolve),
iframeComponent: () => import('@/views/map/index'),
name: 'Map',
meta: { title: '查看地图', affix: true }
}
]
},
- 在含router-view的主页面,初始化时,将含iframeComponent的路由信息都收集起来,声明并渲染component,此时v-show控制属性值为false;
created(){
// 设置iframe页的数组对象
const componentsArr = this.getComponentsArr();
componentsArr.forEach((item) => {
// Vue.component(item.name, item.component);
Vue.component(item.children[0].name, item.children[0].component);
});
this.componentsArr = componentsArr;
// 判断当前路由是否iframe页
this.isOpenIframePage();
},
// 遍历路由的所有页面,把含有iframeComponent标识的收集起来
getComponentsArr() {
const router = this.$router;
const routes = router.options.routes;
const iframeArr = routes.filter(item=>{
if(item.children){
return item.children[0].iframeComponent;
}
});
return iframeArr.map(item=>{
if(item.children[0]){
const name = item.children[0].name || item.children[0].path.replace('/','');
item.children[0] = {
name: name,
path: item.children[0].path,
hasOpen: false,
meta: item.children[0].meta,
component: item.children[0].iframeComponent
};
return item;
}
});
}
- 监听$route,判断当前路由为iframe页面的时候,v-show控制属性值为true;否则为false;
watch: {
$route() {
// console.log('watch route:', this.$route);
// 判断当前路由是否iframe页
this.isOpenIframePage();
}
},
// 根据当前路由设置hasOpen
isOpenIframePage() {
const target = this.componentsArr.find(item => {
return item.children[0].path === this.$route.path.replace('/','')
});
if (target) {
target.children[0].hasOpen = true;
}
// 跳转到查看地图页面时,如果有定位信息,定位到特定经纬度;
if(this.$route.path==='/map'){
let frame = document.getElementById("mapView");
if(frame){
if(this.$route.query){
let landId = this.$route.query.landId? this.$route.query.landId : undefined;
let landCode = this.$route.query.landCode? this.$route.query.landCode : undefined;
let longitude = this.$route.query.longitude? this.$route.query.longitude : undefined;
let latitude = this.$route.query.latitude? this.$route.query.latitude : undefined;
// console.log('this.landCode:', landId, landCode, longitude, latitude);
// 调用定位函数;
frame.contentWindow.dingwei_point(landCode, longitude, latitude);
frame.contentWindow.landId = landId;
frame.contentWindow.landCode = landCode;
}
}
}
},
html模板部分:
<keep-alive :include="cachedViews">
<router-view :key="key"/>
</keep-alive>
<!--iframe页面:在切换含iframe页的界面时利用v-show来控制显示隐藏,使iframe的节点不被删除,以此来防止界面节点被重新更新,从而达到保存iframe节点数据的效果-->
<component
v-for="item in hasOpenComponentsArr"
:key="item.children[0].name"
:is="item.children[0].name"
v-show="($route.path.replace('/','')===item.children[0].path && item.children[0].hasOpen)"
>
</component>