【vue与iframe通讯】

news2024/9/20 5:59:32

vue 与 iframe 通讯

  • 发送数据
    • vue 向 iframe 发送数据
    • iframe 向 vue 发送数据
    • 接收信息( vue & iframe 通用)
  • 实现相互通讯
    • 通讯流程图
    • 实现代码
      • vue 页面
      • iframe页面
      • iframe 内部重定向访问地址,更新 vue 路由
  • 访问跨域
  • 代码下载

前言:vue嵌套iframe实现步骤

发送数据

vue 向 iframe 发送数据

	// utils/common.js
 
	/** vue向iframe发送数据
	  * content iframe.contentWindow
	  * type 事件类型
	  * data 传送的数据
	  */
	export function sendPostMessage(content, type, data = {}) {
		content.postMessage({ type, data }, '*');
	}

iframe 向 vue 发送数据

 // update.html & base.html & includes.html ...
 
 function sendPostMessage(type, data = {}) {
     window.parent.postMessage({ type, data }, "*");
 }

接收信息( vue & iframe 通用)

实例化PubSub时, 入参需提前定义,不然接收不到消息

  // utils/iframe-message.js
  
  /**
   * 接收页面 postMessage 发送的信息
   * Pubsub提供多种类型供订阅,使用方法如下:
   * 1. 需要接收webSocket的地方,import eventsPub from '本文件路径'
   * 2. eventsPub.on(类型, callback)
   *    例:
   *      const receive = data => console.log('eventName', data)
   *      eventsPub.on('eventName', receive)
   * 3.不需要继续接收时调用
   *    eventsPub.remove("eventName", receive) 移除callback
   */

  /** 重要: postMessageEvent 中的 type 需提前定义 */
  class PubSub {
    list = {};
    constructor(events) {
      this.list = {};
      events.forEach(v => {
        this.list[v] = [];
      });
    }

    on(ev, callback) {
      if (this.list[ev]) {
        this.list[ev].push(callback);
        return true;
      } else {
        return false;
      }
    }

    emit(ev, data) {
      // data拷贝: 防止其他callback修改data
      const dataStr = JSON.stringify(data);
      if (this.list[ev]) {
        this.list[ev].forEach((v) => {
          try {
            v(JSON.parse(dataStr));
          } catch (err) {
            console.log("callback error:", err, v);
          }
        });
        return true;
      } else {
        return false;
      }
    }

    remove(ev, callback) {
      if (callback && this.list[ev]) {
        this.list[ev].forEach((v, i) => {
          if (v === callback) {
            this.list[ev].splice(i, 1);
          }
        });
        return true;
      } else {
        return false;
      }
    }
  }
  // 订阅的类型需要在postMessageEvent中提前定义好
  const postMessageEvent = ["PAGE_ISREADY"]
  const eventsPub = new PubSub(postMessageEvent);
  window.addEventListener("message", function (e) {
    if (e.data?.type) {
      eventsPub.emit(e.data.type, e.data.data)
    }
  });

  export default eventsPub;

实现相互通讯

通讯流程图

vue路由更新 及 iframe地址刷新时,两者之间的通讯流程
流程图

实现代码

vue 页面

  // IframeTemplate.vue
  
  import { onMounted, onBeforeUnmount } from "vue";
  import eventsPub from "@utils/iframe-message.js"
  import { sendPostMessage } from "@utils/common.js"

  onMounted(() => {
    // 接收信息
    eventsPub.on("PAGE_ISREADY", pageIsReady)
  });

  onBeforeUnmount(() => {
    eventsPub.remove("PAGE_ISREADY", pageIsReady)
  });

  function pageIsReady() {
      // console.log("PAGE_ISREADY")
      updateIframeLoginInfo()
  }

  // 发送信息
  /** iframe 页面登录信息同步 */
  function updateIframeLoginInfo() {
    const iframeWindow = $("#common-iframe")[0].contentWindow
    sendPostMessage(iframeWindow, "LOGIN_INFO", {
      token: localStorage.getItem("TOKEN"),
      userInfo: localStorage.getItem("USER") || "{}"
    })
  }

iframe页面

	// utils/iframe-message.js
	  
	// 将该文件写成原生写法: 删除 remove 之后的代码
	// 添加下边的代码
	
	/** 创建消息接收实例 */
	const postMessageEvent = ["LOGIN_INFO"]
	const eventsPub = new PubSub(postMessageEvent);
	
	/** 接收父页面的消息 */
	window.addEventListener("message", function (e) {
		if (e.data?.type) {
			eventsPub.emit(e.data.type, e.data.data)
		}
	});
	
	/** 发送消息 */
	function sendPostMessage(type, data = {}) {
		window.parent.postMessage({ type, data }, "*");
	}
  // base.html、includes.html、update.html...
  
  // 在所有的页面中引入iframe-message.js、jquery.js
  <script type="text/javascript" src="./js/jquery.js"></script>
  <script type="text/javascript" src="./js/iframe-message.js"></script>
  // 并添加下边的代码
  <script type="text/javascript">

    /** 获取当前登录用户信息并存储 */
    function setUserInfo(data) {
      const { token, userInfo } = data;
      const curToken = localStorage.getItem("TOKEN")
      const curUser = localStorage.getItem("USER")
      curToken != token && localStorage.setItem("TOKEN", token)
      curUser != userInfo && localStorage.setItem("USER", userInfo)
    }

    $(document).ready(() => {
      // GET VUE MESSAGE
      eventsPub.on("LOGIN_INFO", setUserInfo)

      // NOTIFY VUE MESSAGE
      sendPostMessage("PAGE_ISREADY", { iframeIsReady: true })
    })
  </script>

iframe 内部重定向访问地址,更新 vue 路由

需将iframe的地址添加到vue路由上

  1. iframe页面判断是否是内部跳转,并将页面地址发送到vue

        // base.html...
        
        function setUserInfo(data) {
            // 其他...
            localStorage.setItem("FROM_PARENT", true)
        }
        $(document).ready(() => {
            // 其他...
            /** iframe内部页面跳转,加载完成 -  */
            const fromParent = localStorage.getItem("FROM_PARENT")
            localStorage.removeItem("FROM_PARENT")
            // 判断是否是vue 页面重定向的
            const { pathname, href, search } = window.location
            let path = pathname.split(".")[0];
            sendPostMessage("PAGE_ISREADY", !fromParent ? {} : { path })
        })
        ```
    
    
  2. vue 接收到地址后,页面路由修改,但iframe页面不需要再刷新

        // IframeTemplate.vue
        
        // 监听路由变更
        watch(route, () => {
          const historyParams = history.state.params
          // 只更新路由时,iframe 页面地址不更新
          if (historyParams && historyParams.justRoute && isFrameSrcUpdate == route.path && !isMounted) {
            isFrameSrcUpdate = "";
            return;
          }
          // iframe 页面地址更新
          createIframe()
        });
        
        /** iframe 页面加载完毕
         * 1. 登陆信息同步
         * 2. iframe 内部跳转,页面地址变化后,vue route也修改(但页面不刷新)
         */
        function pageIsReady(data) {
          updateIframeLoginInfo()
          if (data?.path) {
            let { path, name, query } = data
            isFrameSrcUpdate = path;
            const exit = router.getRoutes().find(i => i.path == path)
            /** iframe 发送了一个未添加路由的页面
             *  1. 添加该页面路由,为能正常访问
             *  2. 在当前页面刷新后,会有路由不存在的问题,
             *    需在整体添加路由的位置将当前页面添加进进去
             */
            !exit && router.addRoute({
              path,
              name,
              meta: { isIframe: true },
              component: () => import("../views/IframePage.vue")
            })
            // justRoute:只更新路由,不刷新页面
            router.push({ path, query, state: { params: { justRoute: true } } });
          }
        }
    

访问跨域

  • 问题:
    部署到环境上后,vue页面访问iframe地址会有访问跨域问题。
  • 解决方案:
    在部署vue 服务器配置时允许访问iframe的域名。
    如: Apache 部署vue 的服务器配置上添加一行配置:Header always append X-Frame-Options <iframe访问的域名>

代码下载

查看代码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1702939.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML+CSS+JavaScript网页制作案例教程第2版-黑马程序员-第9章动手实践

文章目录 效果代码网盘 效果 代码 index.html <!doctype html> <html> <head> <meta charset"utf-8"> <title>通栏效果</title> <link rel"stylesheet" type"text/css" href"index.css"> …

【STM32踩坑】HAL固件库版本过高导致烧录后无法运行问题

问题引入 目前STM32CUBEMX已经更新到了6.11版本&#xff0c;对应的固件库也一直在更新&#xff1b; 以STM32F1库为例&#xff0c;目前最新的库对应版本为1.8.5 但是我们会发现&#xff0c;如果直接使用1.8.5版本的固件库生成HAL源码后&#xff0c;烧录是可以烧录&#xff0c;但…

程序无法监听端口,但netstat -aon | findstr却显示该端口未被占用

程序无法监听端口&#xff0c;但netstat -aon | findstr却显示该端口未被占用 ⚙️1.软件环境⚙️&#x1f50d;2.问题描述&#x1f50d;&#x1f421;3.解决方法&#x1f421;&#x1f914;4.结果预览&#x1f914; ⚙️1.软件环境⚙️ Windows10 教育版64位 &#x1f50d;2.问…

P1115 最长子段和

题目描述 给出一个长度为 &#x1d45b;n 的序列 &#x1d44e;a&#xff0c;选出其中连续且非空的一段使得这段和最大。 输入格式 第一行是一个整数&#xff0c;表示序列的长度 &#x1d45b;。 第二行有 &#x1d45b;n 个整数&#xff0c;第 &#x1d456; 个整数表示序列的…

知识存储概述

文章目录 知识存储概述知识存储方式知识存储基础工具技术发展趋势 知识存储是针对知识图谱的知识表示形式设计底层存储方式&#xff0c;完成各类知识的存储&#xff0c;以支持对大规模图数据的有效管理和计算。知识存储的对象包括基本属性知识、关联知识、事件知识、时序知识和…

Overall Accuracy(OA)、Average Accuracy(AAcc)计算公式

四个重要的指标&#xff1a; True Positive&#xff08;TP&#xff09;、False Positive&#xff08;FP&#xff09;、True Negative&#xff08;TN&#xff09;和False Negative&#xff08;FN&#xff09;。 TP表示分类器预测结果为正样本&#xff0c;实际也为正样本&#xf…

以一道简单的例题计算灵敏性分析

在例1.1中&#xff0c;全部的变量包括&#xff1a;猪的重量w(磅),从现在到出售猪期间经历的时间t(天),t天内饲养猪的花费C(美元),猪的市场价格p(美元/磅),售出生猪所获得的收益R(美元),我们最终获得的净收益P(美元).这里还有一些其他的有关量&#xff0c;如猪的初始重量(200磅)…

看看我一天鼠标点击多少次,键盘点击多少次

1、说明 前一段时间看到新闻,公司监控员工的一天中使用键盘数据次数,员工键盘和鼠标点击次数太少而被辞退。真是让人气愤,真是万恶的资本家呀。 我赶紧看看我一天工作下来我点击了多少次键盘和鼠标,可是我怎么知道呢,咱是干啥的呀,干脆写个小软件统计一下我一天点了多少…

3d火灾救援模拟仿真培训软件复用性强

消防VR安全逃生体验系统是深圳VR公司华锐视点引入了前沿的VR虚拟现实、web3d开发和多媒体交互技术&#xff0c;为用户打造了一个逼真的火灾现场应急逃生模拟演练环境。 相比传统的消防逃生模拟演练&#xff0c;消防VR安全逃生体验系统包含知识讲解和模拟实训演练&#xff0c;体…

Redis篇 数据的编码方式和单线程模型

编码方式和单线程模型 一.redis中的数据类型二. Redis中查询编码方式命令三. 单线程模型四. 经典面试题,redis为何这么快?什么是IO多路复用? 一.redis中的数据类型 在redis中,数据类型大致分为5种 1.字符串类型 2.哈希 3.列表 4.集合 5.有序集合 redis底层在实现这些数据结构…

AI性价比之最、国产化后浪香橙派 AIpro深度体验

目录 前言硬件上手分析第一印象硬件参数分析主控猜测电源分析壳子分析软件测试tf卡镜像烧录与上电开机板卡的连接芯片确认与算力测试体验AI应用样例大模型试用CPU性能测试与升级其他试用记录SATA SSD启动使用感受与场景需求分析使用感受场景需求分析无人机应用场景智慧城市IOT领…

linux 查看csv文件,按指定列聚合 排序

在Linux中&#xff0c;你可以使用awk工具来查看CSV文件的内容&#xff0c;并按照指定的列进行聚合。awk是一种强大的文本处理工具&#xff0c;它可以处理文本文件中的数据&#xff0c;并根据条件执行相应的操作。 以下是一个示例&#xff0c;假设你有一个名为data.csv的CSV文件…

ES学习圣经:从0到1, 精通 ElasticSearch 工业级使用

尼恩&#xff1a;百亿级数据存储架构起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试机会&#xff0c…

LeetCode第131场双周赛C++题解

3158.求出出现两次数字的XOR值 给你一个数组 nums &#xff0c;数组中的数字 要么 出现一次&#xff0c;要么 出现两次。 请你返回数组中所有出现两次数字的按位 XOR 值&#xff0c;如果没有数字出现过两次&#xff0c;返回 0 。 示例 1&#xff1a; 输入&#xff1a;nums …

我被恐吓了,对方扬言要压测我的网站

大家好我是聪&#xff0c;昨天真是水逆&#xff0c;在技术群里交流问题&#xff0c;竟然被人身攻击了&#xff01;骂的话太难听具体就不加讨论了&#xff0c;人身攻击我可以接受&#xff0c;我接受不了他竟然说要刷我接口&#xff01;&#xff01;&#xff01;&#xff01;这下…

对于创建相关项目时,项目出现红色感叹号,且无jre环境显示,应该怎么解决?

首先&#xff0c;假设你已经下载好了相关你的jre环境&#xff0c;注意&#xff1a;如果你的jre不想用之前用的默认的话&#xff0c;你应该新建一个新的文件路径来存储你的新的jre环境下的项目文件。 先直接new->project->javaproject 点击next: 显示如下&#xff1a;&…

Vue实现二维码的展示及下载

个人介绍 hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的…

技术贴 | Query 物理计划构建指南

在往期博客《执行器 - Query 执行详解》中&#xff0c;我们介绍到到一条 Query 的 SQL 语句需要经过&#xff1a;词法分析 —— 生成 AST 语法树 —— 生成物理计划。本期博客我们接续上篇讲解一条 Query 语句物理计划的具体结构&#xff0c;以及如何构建物理计划。 物理计划是…

AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月27日预测第3弹

今天继续基于8883的大底&#xff0c;使用尽可能少的条件进行缩号&#xff0c;同时&#xff0c;今天同样准备两套方案&#xff0c;一套是我自己的条件进行缩号&#xff0c;另外一套是8883的大底结合某位彩友的2码不定位奖号预测二次缩水来杀号。好了&#xff0c;直接上结果吧~ …

多波段光源 通过8种波长实现的成像解决方案

光源在机器视觉中的重要性不容小觑&#xff0c;它直接影响到图像的质量&#xff0c;进而影响整个系统的性能。光源的作用包括提供足够的照明&#xff0c;并确保被摄物体的特征能够被准确地捕捉到图像中&#xff0c;使被检测物体产生清晰的图像&#xff0c;提高图像的对比度和亮…