Vue微前端新探:iframe优雅升级,扬长避短,重获新生

简介: Vue微前端新探:iframe优雅升级,扬长避短,重获新生

一、微前端是什么

微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。


简单来说,就是利用一系列工具和技术,将各个团队的UI页面 组装成用户可以连贯的应用程序。


微前端是最近几年火起来的概念,iframe是早期实现微前端的理想方案,而现在有了其它的方案,比如qianduan框架,single-spa,以及webpack5带来的联邦模块方案。但是每一个方案都有其优缺点,感兴趣的可以去实践一下。


二、iframe全新的微前端方案

iframe是一个天然的微前端方案,但受限于跨域的严格限制而无法很好的应用,本文介绍一种基于iframe优雅实现全新的微前端方案,继承iframe的优点,补足 iframe 的缺点,让 iframe 焕发新生。

前端开发中我们对 iframe 已经非常熟悉了,那么 iframe 的作用是什么?可以归纳如下:

在之前使用iframe的时候,是在页面的使用中引入另外一个页面进行渲染,所以它的基本功能是:在一个web应用中独立的运行另一个web应用


三、iframe的使用优点

  • 非常简单,使用没有任何心智负担
  • 隔离完美,无论是 js、css、dom 都完全隔离开来
  • 多应用激活,页面上可以摆放多个 iframe 来组合业务


四、iframe的使用缺点

  • 路由状态丢失,刷新一下,iframe 的 url 状态就丢失了
  • dom 割裂严重,弹窗只能在 iframe 内部展示,无法覆盖全局
  • 通信非常困难,只能通过 postmessage 传递序列化的消息

能否打造一个完美的 iframe ,保留所有的优点的同时,解决掉所有的缺点呢?

本文以vue2为例,搭建一个左侧导航与顶部导航的二级导航的iframe框架项目。

五、实现步骤

1、先创建一个基座项目,项目只有导航框架,没有页面,不需要路由。

所有功能都在App.vue实现

2、直接在App.vue里写结构
<div class="el-container">
    <div class="el-menu">左侧一级导航</div>
    <div class="el-main">
        <div class="el-header">右侧顶部二级导航</div>
        <div class="el-aside" id="iframeBox">iframe的容器</div>
    </div>
</div>
3、渲染导航数据

这里是data数据部分

data() {
    return {
      index1: 0, //一级导航当前下标
      index2: 0, //二级导航当前下标
      forWard: true, //是否记录路由
      isOpen: false, //是否打开弹窗
      menuTree: [
        {
          id: "1",
          name: "menu1",
          order: 10,
          subMenu: [
            {
              id: "11",
              name: "mneu1_sub1",
              order: 11,
              subMenu: null,
              text: "二级菜单11",
              url: "http://127.0.0.1:5500/js/alert.html",
            },
          ],
          text: "一级菜单1",
          url: "",
        },
      ],
    };
4、添加iframe标签

当点击导航时,触发该事件,动态添加iframe标签

//显示iframe
replaceUrlFun() {
  const bigNode = document.getElementById("iframeBox");
  const contentIframe = document.getElementById("contentIframe");
  if (contentIframe) {
    contentIframe.remove();
  }
  const { index1, index2, menuTree } = this;
  const url1 = menuTree[index1].url;
  const url2 = menuTree[index1].subMenu?.[index2]?.url || "";
  let url = url2 || url1;
  const iframeCon = document.createElement("iframe");
  bigNode.appendChild(iframeCon);
  iframeCon.setAttribute("class", "iframe");
  iframeCon.setAttribute("id", "contentIframe");
  iframeCon.setAttribute("frameborder", 0);
  iframeCon.setAttribute("allowfullscreen", true);
  iframeCon.src = url;
},


六、需要解决的一些问题

1、项目之间的通讯

使用postMessage方法来完成基座项目和子项目之间的通讯。

2、iframe的弹窗及遮罩层问题

将弹出层代码写到父页面中,子页面使用postMessage方法发送消息告诉父页面打开,关闭弹层,父页面监听打开,关闭弹层。

<!-- 父页面弹窗蒙层 -->
<div class="openDiv" v-if="isOpen"></div>

//监听子应用消息
window.addEventListener(
  "message",
  function (event) {
    if (event.data == "openDiv") {
      that.openDiv();
    }
    if (event.data == "closeDiv") {
      that.closeDiv();
    }
  },
  false
);

遇到问题:父页面弹出层会把整个的iframe遮住。


解决方案:

1.父页面弹出层设置position: fixed;z-index: 100;

2.给ifame设置position: relative;z-index: 200;

3.子页面也要设置遮罩层,遮住ifame区域。position: fixed;z-inde

4.设置弹窗容器,position: fixed;z-index: 400;

5.子页面事件,打开弹窗,向父页面发消息

6.父页面事件,监听消息,打开弹窗

<div class="box">
    <button @click="openDiv">弹窗</button>
</div>
<!-- 子页面弹窗蒙层 -->
<div class="openDiv" v-if="isOpen">
    <div class="openBox" @click="closeDiv">点击关闭</div>
</div>
// 子页面事件
openDiv() {
    // 向父窗口发送消息
    window.top.postMessage('openDiv', '*');
    this.isOpen = true;
},
closeDiv() {
    // 向父窗口发送消息
    window.top.postMessage('closeDiv', '*');
    this.isOpen = false;
},
3、iframe里的全屏问题

全屏方案,原生方法使用的是 Element.requestFullscreen(),iframe 标签设置 allowfullscreen=“true” 属性

//全屏事件
fullscreen() {
    const bigNode = document.getElementById("app");
    bigNode.requestFullscreen()
}
4、组件复用问题

公共组件可以单独提出来放到一个单独的项目里,在项目中把公共组件全部暴露出来供其它项目安装使用,也就是说主项目和子项目可以选择性安装需要的组件。

5、浏览器的后退问题

iframe 和主页面共用一个浏览历史,iframe 会影响页面的前进后退。并且 iframe 页面刷新会重置,因为浏览器的地址栏没有变化,iframe 的 src 也没有变化。


iframe页面外部的跳转尽管不会让浏览器地址栏发生变化,然而却会产生一个看不见的“history记录”,也就是点击后退或后退按钮(history.forward()或history.back())能够让iframe页面也后退后退,然而地址栏无任何变动。


所以精确来说后退无需咱们做任何解决,咱们要做的就是让浏览器地址栏同步更新即可。

当点击导航时,触发该事件,更新URL
//记录路由方法
routerKeyArrFun() {
  if (!this.forWard) return;
  const { index1, index2, menuTree } = this;
  const name1 = menuTree[index1]?.name || "";
  const name2 = menuTree[index1]?.subMenu?.[index2]?.name || "";
  if (name1) {
    const url = `#/?${name1}${name2 ? `#${name2}` : ""}`;
    history.pushState(null, null, url);
  }
},
6、刷新的问题

保障URL同步更新须要满足这3种状况:

  • 页面刷新,iframe可以加载正确页面;
  • 页面跳转,浏览器地址栏可能正确更新;
  • 点击浏览器的后退,地址栏和iframe都可能同步变动;
上面我们已经把路由信息记录并更新了URL地址。所以每当刷新或后退的时候,只要解析URL就可以了
//解析浏览器信息
getUrlModuleInfo() {
  this.forWard = false; //记录地址开关
  const { menuTree } = this;
  const ohref = window.location.href;
  const len = ohref.indexOf("?");
  if (len < 0) {
    this.selectFirstMenu();
    this.forWard = true;
    return;
  }
  const params = ohref.substring(len + 1).split("#");
  const [first, second] = params;
  menuTree.forEach((item, index) => {
    if (item.name !== first) return;
    this.selectFirstMenu(index);
    if (!second) return;
    item.subMenu?.forEach((sub, i) => {
      if (sub.name !== second) return;
      this.selectSecondMenu(i);
    });
  });
  this.forWard = true;
},
7、实现子应用免登录
7.1、跨域共享cookie

在XMLHttpRequest v2标准下,提出了CORS(Cross Origin Resourse-Sharing)的模型,试图提供安全方便的跨域读写资源。目前主流浏览器均支持CORS。(IE10+)

7.2、代理跨域共享Cookie

当我们的请求需要经过代理服务器时,可以将请求转发到同一个域名下的不同端口,这样就可以共享Cookie了。例如,假设服务器在8080端口,而我们需要共享Cookie,可以使用Nginx配置一个反向代理来实现。

server {
    listen 80;
    server_name xxx.com;
    location / {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
    }
}
7.3、Json Web Token

前后端分离的项目中,可以使用JWT(Json Web Token)来进行身份验证,并用它来代替Cookie来实现跨域共享。


七、界面效果

目录
相关文章
|
4月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
448 1
|
5月前
|
移动开发 前端开发 JavaScript
Vue与React两大前端框架的主要差异点
以上就是Vue和React的主要差异点,希望对你有所帮助。在选择使用哪一个框架时,需要根据项目的具体需求和团队的技术栈来决定。
358 83
|
4月前
|
JavaScript 前端开发 编译器
Vue与TypeScript:如何实现更强大的前端开发
Vue.js 以其简洁的语法和灵活的架构在前端开发中广受欢迎,而 TypeScript 作为一种静态类型语言,为 JavaScript 提供了强大的类型系统和编译时检查。将 Vue.js 与 TypeScript 结合使用,不仅可以提升代码的可维护性和可扩展性,还能减少运行时错误,提高开发效率。本文将介绍如何在 Vue.js 项目中使用 TypeScript,并通过一些代码示例展示其强大功能。
208 22
|
6月前
|
人工智能 JavaScript 前端开发
Vue 性能革命:揭秘前端优化的终极技巧;Vue优化技巧,解决Vue项目卡顿问题
Vue在处理少量数据和有限dom的情况下技术已经非常成熟了,但现在随着AI时代的到来,海量数据场景会越来越多,Vue优化技巧也是必备技能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
JavaScript 前端开发 搜索推荐
Vue的数据驱动视图与其他前端框架的数据驱动方式有何不同?
总的来说,Vue 的数据驱动视图在诸多方面展现出独特的优势,其与其他前端框架的数据驱动方式的不同之处主要体现在绑定方式、性能表现、触发机制、组件化结合、灵活性、语法表达以及与后端数据交互等方面。这些差异使得 Vue 在前端开发领域具有独特的地位和价值。
208 58
|
8月前
|
JavaScript 前端开发 jenkins
抛弃node和vscode,如何用记事本开发出一个完整的vue前端项目
本文探讨了在不依赖Node和VSCode的情况下,仅使用记事本和浏览器开发一个完整的Vue3前端项目的方法。通过CDN引入Vue、Vue Router、Element-UI等库,直接编写HTML文件实现页面功能,展示了前端开发的本质是生成HTML。虽然日常开发离不开现代工具,但掌握这种基础方法有助于快速实现想法或应对特殊环境限制。文章还介绍了如何用Node简单部署HTML文件到服务器,提供了一种高效、轻量的开发思路。
172 10
|
10月前
|
前端开发 JavaScript 开发者
React与Vue:前端框架的巅峰对决与选择策略
【10月更文挑战第23天】React与Vue:前端框架的巅峰对决与选择策略
|
10月前
|
前端开发 JavaScript 数据管理
React与Vue:两大前端框架的较量与选择策略
【10月更文挑战第23天】React与Vue:两大前端框架的较量与选择策略
|
11月前
|
JavaScript 前端开发 算法
前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
420 2
|
11月前
|
前端开发 JavaScript API
2025年前端框架是该选vue还是react?有了大模型-例如通义灵码辅助编码,就不用纠结了!vue用的多选react,react用的多选vue
本文比较了Vue和React两大前端框架,从状态管理、数据流、依赖注入、组件管理等方面进行了详细对比。当前版本和下载量数据显示React更为流行,但Vue在国内用户量增长迅速。Vue 3通过组合式API提供了更灵活的状态管理和组件逻辑复用,适合中小型项目;React则更适合大型项目和复杂交互逻辑。文章还给出了选型建议,强调了多框架学习的重要性,认为技术问题已不再是选型的关键,熟悉各框架的最佳实践更为重要。
6810 1