Vue中对iframe实现keep alive无刷新的方法


Posted in Javascript onJuly 23, 2019

前言

最近一个需求,需要在 Vue 项目中加入 含有iframe 的页面,同时在路由切换的过程中,要求iframe的内容 不会被刷新 。一开始使用了Vue自带的keep- alive发现没有用,于是自己研究了一下解决方案。。。。。。

Vue的keep-alive原理

要实现对保持iframe页的状态。我们先搞清楚为什么Vue的keep-alive不能凑效。keep-alive原理是把组件里的节点信息保留在了 VNode (在内存里),在需要渲染时候从Vnode渲染到真实DOM上。iframe页里的内容并不属于节点的信息,所以使用keep-alive依然会重新渲染iframe内的内容。 另外 ,我也尝试有过想法:如果把整个iframe节点保存起来,然后需要切换时把它渲染到目标节点上,能否实现iframe页不被刷新呢?————也是不可行的,iframe每一次渲染就相当于打开一个新的网页窗口,即使把节点保存下来,在渲染时iframe页还是刷新的。

实现的思路

既然保持iframe页里的状态很难实现,在这个时候我想到了一个别的方法。能否在Vue的route-view节点上动点手脚?使得在切换 非iframe页 的时候使用Vue的路由,当切换 iframe页 时则使用 v-show 切换显示与隐藏,使得iframe节点 一直不被删除 ,这样就能保持iframe的状态了。

我们简陋的实现一下以上的效果,上代码:

入口main.js:

import Vue from 'vue/dist/vue.js'
import App from './App.vue'
import VueRouter from 'vue-router';

const Index = { template: '<div>Index</div>' }
const routes = [
 // 含有iframe的两个页面
 {
 path: '/f1',
 name: 'f1'
 },
 // 含有iframe的两个页面
 {
 path: '/f2',
 name: 'f2'
 },
 {
 path: '/index',
 component: Index
 }
]

const router = new VueRouter({
 routes
});

Vue.use(VueRouter);
new Vue({
 render: h => h(App),
 router
}).$mount('#app')

根组件:

<template>
 <div id="app">
 <div class="nav">
  <router-link class="router" to="/f1">Go to F1</router-link>
  <router-link class="router" to="/f2">Go to F2</router-link>
  <router-link class="router" to="/index">Go to Index</router-link>
 </div>
 
 <keep-alive>
  <!-- Vue的路由 -->
  <router-view></router-view>
 </keep-alive>
 
 <!-- iframe页面 -->
 <f1 v-show="$route.path == '/f1'"></f1>
 <f2 v-show="$route.path == '/f2'"></f2>
 </div>
</template>

<script>
import F1 from './components/f1';
import F2 from './components/f2';
export default {
 name: 'app',
 components: {
 F1,
 F2
 },
 
}
</script>

上面代码简单来说,关键的地方首先是main.js初始化路由时,对iframe页不填写属性component,这样页面就是空白的。然后在 router-view 节点旁边渲染iframe页组件,使用$route.path判断当前路由的指向,控制iframe页的 显示与隐藏 。

上面代码简单的解决了问题,但还有一些地方可以优化:

  1. iframe页在根节点App.vue一渲染时 已经渲染 了,对此iframe页可以做成 懒加载 ,只有在进入过相应页面了触发渲染,并且渲染过之后就用v-show切换显示与隐藏
  2. 每当增加一个iframe页都要增加一段的组件引入注册和调用的代码。比较 繁琐 。我们目标应该做到每增加一个iframe页,只需要添加尽量少的代码。这里思路是:
    1. 在路由配置中定义一个属性,用于 标识该页面是否含有iframe 的页面
    2. 根据标识,iframe页组件 自动动态注册和渲染 ,无需再手写额外的代码
    3. router-view和iframe切换的逻辑封装成 新组件 ,用它 替代原有的router-view

我们先修改router的配置,增加一个属性名iframeComponent,用于标识是否包含iframe,该属性的值是组件文件引用

main.js:

import F1 from './components/f1';
import F2 from './components/f2';

const routes = [
 {
 path: '/f1',
 name: 'f1',
 iframeComponent: F1 // 用于标识是否含有iframe页
 },
 {
 path: '/f2',
 name: 'f2',
 iframeComponent: F2 // 用于标识是否含有iframe页
 },
 {
 path: '/index',
 component: { template: '<div>Index</div>' }
 }
]

const router = new VueRouter({
 routes // (缩写)相当于 routes: routes
});

new Vue({
 render: h => h(App),
 router
}).$mount('#app')

接下来我们第二步和第三步结合在一起,封装新的组件iframe-router-view.vue:

<template>
 <div>
  <!-- Vue的router-view -->
  <keep-alive>
   <router-view></router-view>
  </keep-alive>

  <!-- iframe页 -->
  <component
   v-for="item in hasOpenComponentsArr"
   :key="item.name"
   :is="item.name"
   v-show="$route.path === item.path"
  ></component>
 </div>
</template>

<script>
import Vue from 'vue/dist/vue.js'
export default {
 created() {
  // 设置iframe页的数组对象
  const componentsArr = this.getComponentsArr();
  componentsArr.forEach((item) => {
   Vue.component(item.name, item.component);
  });
  this.componentsArr = componentsArr;
  // 判断当前路由是否iframe页
  this.isOpenIframePage();
 },
 data() {
  return {
   componentsArr: [] // 含有iframe的页面
  }
 },
 watch: {
  $route() {
   // 判断当前路由是否iframe页
   this.isOpenIframePage();
  }
 },
 computed: {
  // 实现懒加载,只渲染已经打开过(hasOpen:true)的iframe页
  hasOpenComponentsArr() {
   return this.componentsArr.filter(item => item.hasOpen);
  }
 },
 methods: {
  // 根据当前路由设置hasOpen
  isOpenIframePage() {
   const target = this.componentsArr.find(item => {
    return item.path === this.$route.path
   });
   if (target && !target.hasOpen) {
    target.hasOpen = true;
   }
  },
  // 遍历路由的所有页面,把含有iframeComponent标识的收集起来
  getComponentsArr() {
   const router = this.$router;
   const routes = router.options.routes;
   const iframeArr = routes.filter(item => item.iframeComponent);
   
   return iframeArr.map((item) => {
    const name = item.name || item.path.replace('/', '');
    return {
     name: name,
     path: item.path,
     hasOpen: false, // 是否打开过,默认false
     component: item.iframeComponent // 组件文件的引用
    };
   });
  }
 }
}
</script>
  1. 该组件主要做的是根据main.ja里的routes生成一个只含有iframe页的数组对象。
  2. watch上监听$route,判断当前页面在iframe页列表里的话就设置hasOpen属性为true,渲染该组件
  3. 用v-show="$route.path === item.path"切换iframe页的显示与隐藏。

逻辑并不复杂,这里就不多赘述。

结语

大家如果有更好的实现方法,或者我上面还有什么需要更正的错误,欢迎交流。 上面demo的代码放在了个人github上 https://github.com/jmx164491960/vue-iframe-demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript学习笔记(三)显示当时时间的代码
Apr 08 Javascript
让图片旋转任意角度及JQuery插件使用介绍
Mar 20 Javascript
jQuery实现动画效果的实例代码
May 07 Javascript
JavaScript中for..in循环陷阱介绍
Nov 12 Javascript
String.prototype实现的一些javascript函数介绍
Nov 22 Javascript
搭建pomelo 开发环境
Jun 24 Javascript
关于javascript原型的修改与重写(覆盖)差别详解
Aug 31 Javascript
浅谈jquery上下滑动的注意事项
Oct 13 Javascript
微信小程序排坑指南详解
May 23 Javascript
使用D3.js构建实时图形的示例代码
Aug 28 Javascript
详解如何创建并发布一个 vue 组件
Nov 08 Javascript
vue element table中自定义一些input的验证操作
Jul 18 Javascript
jQuery Ajax async=&gt;false异步改为同步时,解决导致浏览器假死的问题
Jul 22 #jQuery
这应该是最详细的响应式系统讲解了
Jul 22 #Javascript
20道JS原理题助你面试一臂之力(必看)
Jul 22 #Javascript
微信小程序webview 脚手架使用详解
Jul 22 #Javascript
koa2 用户注册、登录校验与加盐加密的实现方法
Jul 22 #Javascript
koa2服务端使用jwt进行鉴权及路由权限分发的流程分析
Jul 22 #Javascript
在小程序中推送模板消息的实现方法
Jul 22 #Javascript
You might like
php环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
2006/11/17 PHP
PHP实现发送邮件的方法(基于简单邮件发送类)
2015/12/17 PHP
Jquery数独游戏解析(一)-页面布局
2010/11/05 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
2013/03/29 Javascript
关于jQuery参考实例 1.0 jQuery的哲学
2013/04/07 Javascript
js中继承的几种用法总结(apply,call,prototype)
2013/12/26 Javascript
jQuery实现跨域iframe接口方法调用
2015/03/14 Javascript
JS简单模拟触发按钮点击功能的方法
2015/11/30 Javascript
不得不分享的JavaScript常用方法函数集(下)
2015/12/25 Javascript
AngularJs基于角色的前端访问控制的实现
2016/11/07 Javascript
微信小程序之ES6与事项助手的功能实现
2016/11/30 Javascript
bootstrap模态框跳转到当前模板页面 框消失了而背景存在问题的解决方法
2020/11/30 Javascript
canvas滤镜效果实现代码
2017/02/06 Javascript
React Native 通告消息竖向轮播组件的封装
2020/08/25 Javascript
前端html中jQuery实现对文本的搜索功能并把搜索相关内容显示出来
2017/11/14 jQuery
微信小程序使用image组件显示图片的方法【附源码下载】
2017/12/08 Javascript
vue将对象新增的属性添加到检测序列的方法
2018/02/24 Javascript
angular组件间传值测试的方法详解
2020/05/07 Javascript
逐行分析鸿蒙系统的 JavaScript 框架(推荐)
2020/09/17 Javascript
vue 全局封装loading加载教程(全局监听)
2020/11/05 Javascript
[01:09]2014DOTA2国际邀请赛 TI4西雅图DOTA2 中国美女coser加油助威
2014/07/20 DOTA
初步理解Python进程的信号通讯
2015/04/09 Python
使用Python发送各种形式的邮件的方法汇总
2015/11/09 Python
Python使用Paramiko模块编写脚本进行远程服务器操作
2016/05/05 Python
Python入门必须知道的11个知识点
2018/03/21 Python
Python如何安装第三方模块
2020/05/28 Python
Python绘图之柱形图绘制详解
2020/07/28 Python
HTML5仿手机微信聊天界面
2016/03/18 HTML / CSS
canvas裁剪clip()函数的具体使用
2018/03/01 HTML / CSS
一文彻底解决HTML5页面中长按保存图片功能
2019/06/10 HTML / CSS
美国指甲油品牌:Deco Miami
2017/01/30 全球购物
超市中秋节促销方案
2014/03/21 职场文书
我们的节日春节活动方案
2014/08/22 职场文书
二年级语文上册复习计划
2015/01/19 职场文书
学校禁毒宣传活动总结
2015/05/08 职场文书
员工手册董事长致辞
2015/07/29 职场文书