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 相关文章推荐
js实现运行代码需要刷新的解决方法
Aug 18 Javascript
上传的js验证(图片/文件的扩展名)
Apr 25 Javascript
用js来刷新当前页面保留参数的具体实现
Dec 23 Javascript
jQuery中nextAll()方法用法实例
Jan 07 Javascript
Javascript中的call()方法介绍
Mar 15 Javascript
AngularJS实现全选反选功能
Dec 08 Javascript
基于jQuery实现点击弹出层实例代码
Jan 01 Javascript
本地搭建微信小程序服务器的实现方法
Oct 27 Javascript
Vue手把手教你撸一个 beforeEnter 钩子函数
Apr 24 Javascript
超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法
Jan 27 Javascript
小程序按钮避免多次调用接口和点击方案实现(不用showLoading)
Apr 15 Javascript
vuecli项目构建SSR服务端渲染的实现
Oct 30 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
十大催泪虐心动漫电影,有几部你还没看
2020/03/04 日漫
php中导出数据到excel时数字变为科学计数的解决方法
2013/02/03 PHP
php5.5新数组函数array_column使用
2013/07/08 PHP
解决Codeigniter不能上传rar和zip压缩包问题
2014/03/07 PHP
Yii框架的redis命令使用方法简单示例
2019/10/15 PHP
JQuery 构建客户/服务分离的链接模型中Table分页代码效率初探
2010/01/22 Javascript
jquery 简单图片导航插件jquery.imgNav.js
2010/03/17 Javascript
jquery实现微博文字输入框 输入时显示输入字数 效果实现
2013/07/12 Javascript
javascript实现存储hmtl字符串示例
2014/04/25 Javascript
Nodejs实现的一个简单udp广播服务器、客户端
2014/09/25 NodeJs
Jquery设置attr的disabled属性控制某行显示或者隐藏
2014/09/25 Javascript
详解参数传递四种形式
2015/07/21 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
2016/05/21 Javascript
基于javascript实现的购物商城商品倒计时实例
2016/12/11 Javascript
详解ES6中class的实现原理
2020/10/03 Javascript
Python采用Django制作简易的知乎日报API
2016/08/03 Python
Python yield 使用方法浅析
2017/05/20 Python
JPype实现在python中调用JAVA的实例
2017/07/19 Python
用TensorFlow实现多类支持向量机的示例代码
2018/04/28 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
2018/12/28 Python
Django打印出在数据库中执行的语句问题
2019/07/25 Python
ffmpeg+Python实现B站MP4格式音频与视频的合并示例代码
2020/10/21 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
基于HTML5的WebGL经典3D虚拟机房漫游动画
2017/11/15 HTML / CSS
EJB2和EJB3在架构上的不同点
2014/09/29 面试题
幼儿园毕业教师感言
2014/02/21 职场文书
机关道德讲堂实施方案
2014/03/15 职场文书
美容院店长岗位职责
2014/04/08 职场文书
租房协议书怎么写
2014/04/10 职场文书
无房证明范本
2014/09/17 职场文书
银行稽核岗位职责
2015/04/13 职场文书
学术研讨会主持词
2015/07/04 职场文书
Python OpenCV 图像平移的实现示例
2021/06/04 Python
MySQL系列之一 MariaDB-server安装
2021/07/02 MySQL
nginx服务器的下载安装与使用详解
2021/08/02 Servers
css3带你实现3D转换效果
2022/02/24 HTML / CSS