关于iframe一些通讯的记录(可适用工作流审批,文中有项目实践,欢迎咨询)

news2024/11/29 4:33:28

一.知识点

(1).我们可以通过postMessage(发送方)和onmessage(接收方)这两个HTML5的方法, 来解决跨页面通信问题,或者通过iframe嵌套的不同页面之间的通信

a.父页面代码如下

<div v-if="src" class="iframe">
      <iframe
            ref="iframe"
            id="iframe"
            width="100%"
            height="600"
            loading="lazy"
            :src="src"
            frameborder="0"
            scrolling="no"
            marginheight="0"
            marginwidth="0"
            @load="loaded"
      ></iframe>
</div>

a1.父页面向子页面发送信息(两种方法)

第一种

const iframe = document.getElementId('iframe')//id
//第一个参数是发送的消息,无格式要求;第二个参数是域名限制,当不限制域名时填写*
// 后面的 * 号就是处理跨域问题的,任何域名都不会出现跨域问题
// 传递的参数可以是数组,对象,字符串等 
iframe.contentWindow.postMessage('你需要传的数据', "*"); //数据比如({},'*'),('123','*')
// 也可以指定传送域名地址,这个域名不会出现跨域问题,写父页面(接收)域名地址
iframe.contentWindow.postMessage("需要传递的参数", 'http://0.0.0.0:8080')

第二种

this.$refs.iframe.contentWindow.postMessage(workDetailsData.workflowList,'*')

a2.子页面接收父页面收到的信息

 * 函数防抖
 * @param fn
 * @param interval
 * @returns {Function}
 * @constructor
 */
export const Debounce = (fn, t) => {
  let delay = t || 500
  let timer
  return function () {
    let args = arguments
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      timer = null
      fn.apply(this, args)
    }, delay)
  }
}


import { Debounce } from '@/utils/public.js'
mounted() {
        window.onmessage = this.handleMesg
        // addEventListener触发多次问题
        // window.addEventListener('message', this.handleMesg)
      }
},

//防抖处理
handleMesg: Debounce(function (e) {
    //这里做接收数据的操作
    if(e){
    console.log(e.data)
}

}),

a.3子页面(iframe加载的页面)向父页面传递消息

window.parent.postMessage({string: '我是iframe里面的数据'}, "*");

a.4父页面接收子页面传递的消息

window.onmessage = function(event){
	console.log(event.data.string) //我是iframe里面的数据
}

a.5 父页面接收子页面传递的消息(第二种)

//监听单个事件
window.addEventListener('message', function (msg) {
  console.log(msg.data.string)
})

二.项目实践

1.效果图

编辑

编辑

编辑

逻辑如下

1.首先点击审批通过按钮,调用方法

<el-button
    v-if="hasApproved"
    type="primary"
    size="small"
    @click="submit('Approved')"
  >
    审批通过
</el-button>

2.方法如下

// 审批
  submit(data) {
    this.operateStatus = data //传过来的状态储存起来
    if (this.suspended) { //默认是false  请求详情接口时会根据后端返回这个字段判断他是否挂起
      this.$message.error('该任务已挂起,无法进行操作!')
      return
    }
    if (data === '撤回') {
      this.confirmSubmit()
      return
    }
    let label = data === 'Approved' ? '审批通过' : '审批拒绝'
    this.assignee_schema_model.comment =
      data === 'Approved' ? '批准' : '拒绝'
    this.dialogTitle = `确认是否${label}`
    this.msgContent = `确认${label}吗?`
    this.visible = true //打开弹窗
  },
弹窗如下

3.点击确定调用接口方法,调用接口时进行一些判断操作如下

  confirmSubmit() {
        let data = this.operateStatus
        this.isLoading = true
        if (data === 'Approved' || data == 'Rejected') {
          const params = { //审批流接口需要的参数
             variables: [
              {
                name: 'approveResult',
                value: data === 'Approved' ? 'Approved' : 'Rejected', //判断是同意还是拒绝
              },
              {
                name: 'comment',
                value: this.assignee_schema_model.comment,
              },
              {
                name: 'isWithdraw',
                value: '0',
              },
            ],
            action: 'complete',
            comment: this.assignee_schema_model.comment,
            currentTaskId: this.$route.query.id,
          }
          if (!this.assignee_schema_model.comment) { //判断是否写了批注 不能为空
            this.$message.error('请输入批注!')
            this.isLoading = false
            return
          }
            //重点 这里假如你是需要在自己的页面,比如商品详情页面,即iframe的页面自己调用自己中心的后端接口,不通过公共的审批接口时,需要进入这里,this.isPostMsg这个数据需要自己判断是否需要进入
          if (this.isPostMsg && data == 'Approved') {
            // 审批动作在iframe页面中完成
            this.$refs.iframe.contentWindow.postMessage( //向iframe 页面传递信息
              {
                status: data,
                value: this.assignee_schema_model.comment,
                params: params,
              },
              '*'
            )
            this.visible = false
            this.isLoading = false

            window.addEventListener('message', this.handleMesg) //接收iframe页面传递过来的信息
            return //不往下执行 即不调用公共审批接口
          }

          if (!this.src) { //判断配置
            console.log('审批流配置问题,formKey为空')
            this.$message.error(
              '流程配置问题,/activiti/task接口返回的formKey为空'
            )
            this.visible = false
            this.isLoading = false
            return
          }
          if (!this.isOpenIframe(this.src)) {
            //没有被审批流程的菜单权限
            this.$message.error(this.authMenuMsg)
            this.visible = false
            this.isLoading = false
            return
          }

          taskAction(params) //调用公共审批接口 (包含了同意和拒绝) 根据定义的参数判断
            .then((res) => {
              if (res.failed === true) {
                this.$message.error(res.message || '操作失败,请联系管理员')
                this.isLoading = false
              } else {
                this.$message.success('操作成功')
                this.visible = false
                this.isLoading = false
                this.$store.dispatch( //关闭当前页面路由
                  'tabsBar/delVisitedRoute',
                  this.$route.fullPath
                )
                this.$router.push(`/tcl/tof/message/workflow/wait-list`) //跳转到待办列表页面
              }
            })
            .catch((error) => {
              this.$message.error(error)
              this.isLoading = false
            })
        } else {
          // 撤回
          backAction(this.$route.query.id) //撤回流程公共 接口
            .then((res) => {
              if (res.failed === true) {
                this.$message.error(res.message || '操作失败,请联系管理员')
                this.isLoading = false
              } else {
                this.$message.success('操作成功')
                this.$store.dispatch(
                  'tabsBar/delVisitedRoute',
                  this.$route.fullPath
                )
                // this.$router.go(-1)
                this.visible = false
                this.isLoading = false
                this.$router.push(`/tcl/tof/message/workflow/wait-list`)
              }
            })
            .catch((error) => {
              this.$message.error(error)
              this.isLoading = false
            })
        }
      },

4.父页面的handleMesg方法(重点交互)

//防抖 (debounce): 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
//防抖处理 高频调用
      handleMesg: Debounce(function (e) {
        if (e.data.type == 'getDataDetail') {
        //子页面想要获取待办详情接口数据 会主动发送一个事件过来
        //如判断type是哪个页面过来的
         //这里向子页面发送数据回去
          this.$refs.iframe.contentWindow.postMessage(
            workDetailsData.workflowList, //待办详情接口返回的数据
            '*'
          )
        }
        //这里可以自定义提示信息的操作
        //iframe子页面会发送一个方法过来 如第五点
        if (e.source) {
          if (e.data.status == 'Approved') {
            //补充知识
            //getElementsByClassName() 方法返回文档中所有指定类名的元素集合,作为 NodeList 对象。
            //NodeList 对象代表一个有顺序的节点列表。NodeList 对象 我们可通过节点列表中的节点索引号来访问列表中的节点(索引号由0开始)。
            //提示: 你可以使用 NodeList 对象的 length 属性来确定指定类名的元素个数,并循环各个元素来获取你需要的那个元素。

            let doms = document.getElementsByClassName('el-message')[0]
            if (doms == undefined) {
              this.$message.success('审批通过')
            }

            this.visible = false
            this.$store.dispatch(
              'tabsBar/delVisitedRoute',
              this.$route.fullPath
            )
            if (this.$route.query.type === 'workflow')
              this.$router.push(`/tcl/tof/order/sales/workflow`)
            else this.$router.push(`/tcl/tof/message/workflow/wait-list`)
          } else if (e.data.status == 'Rejected') {
            let doms = document.getElementsByClassName('el-message')[0]
            if (doms == undefined) {
              this.$message.success('审批拒绝')
            }

            this.visible = false
            if (this.$route.query.type === 'workflow')
              this.$router.push(`/tcl/tof/order/sales/workflow`)
            else this.$router.push(`/tcl/tof/message/workflow/wait-list`)
          } 
          } else if (e.data.status == 'innerError') {
            let msgObj = e.data
            this.$message({
              type: msgObj.msgType,
              message: msgObj.msg,
            })
          }
        }
      }),

5.子页面方法

that.postMsgToFrame('缺少附件', 'warning')
postMsgToFrame(msg, errType) {
    if (this.isPorcess) {
      window.parent.postMessage(
        {
          type: 'custAddMsg',
          status: 'innerError',
          msgType: errType,
          msg: msg,
        },
        '*'
      )
    } else {
      this.$message({
        type: errType,
        message: msg,
      })
    }
  },

子页面一开始要获取审批流待办详情接口数据来进行一些判断如下

mounted() {
      // console.log('workDetailsData', workDetailsData)
        //首先向父页面主动发送事件
      if (this.$route.query.type == 'delay') {
        window.parent.postMessage(
          {
            type: 'getDataDetail',
          },
          '*'
        )
        //父页面发送事件过来,这里接收事件和数据,进行对应的操作,如判断该字段在哪个节点是否需要显示
        window.addEventListener('message', (e) => {
          if (e.data) {
            let showNode = []
            if (this.options.nodeStatus && this.options.nodeStatus.length > 0) {
              this.options.nodeStatus.forEach((item) => {
                showNode.push(item.value)
              })
              console.log('这里的数据看看', showNode)
              if (showNode.indexOf(e.data.name) != -1) {
                obsData.isFlagShowCol = true
              }
            }
          }
        })
        
      }
    },

配置平台配置流程

iframe页面判断审批同意接口是否调用自己中心的后端接口

computed: {
    isPorcess: {
        get() {
          let ll = this.$route.query
          if (ll.custPostMsgFlg && ll.custPostMsgFlg.indexOf('true') > -1) {
            return true
          } else {
            return false
          }
        },
      },
}

进入页面在mounted判断,需要节点都挂载完毕,然后在方法methods中调用审批方法,是由父页面点击审批通过发送事件过来进行调用

mounted() {
    if (this.isPorcess) {
      window.addEventListener('message', this.handleMesg)
    }
}
methods: {
    // 点击审批
      async handleMesg(e) {
        console.log('e', e)
        if (e.data.status === 'Approved') { //判断是否同意
          // this.$refs.Address.$refs.tabs.validate()
          this.examineApprove()
        }
      },
    async examineApprove() {
        //先进行表单必填校验操作 通过才调用接口
        let flag = await this.$refs.Address.validateForm()
        this.$refs['commentForm'].validate((isPass) => {
          this.schema_model.comment = this.commentForm.comment //批注自定义
          this.$refs['filterForm'].validate((valid) => {
            //校验
            if (valid && flag && isPass) {
              const loading = this.$baseLoading({
                target: 'document.body.tree',
              })
              subsidyPriceProcess(this.schema_model).then((res) => {
                if (res.success == false) {
                  loading.close()
                  this.$message.error('审批不通过,接口报错')
                } else {
                  loading.close()
                  //iframe 向父组件传值
                  window.parent.postMessage(
                    {
                      type: 'commodityApprove',
                      status: 'Approved',
                    },
                    '*'
                  )
                }
              })
            } else {
              this.$message({
                type: 'error',
                message: '表单校验不通过!',
              })
              return false
            }
          })
        })
      },
}

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

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

相关文章

Kafka进阶篇-消费者详解Flume消费Kafka原理

简介 由于挺多时候如果不太熟系kafka消费者详细的话&#xff0c;很容易产生问题&#xff0c;所有剖析一定的原理很重要。 Kafka消费者图解 消费方式 消费者总体工作流程 消费者组初始化流程 消费者详细消费流程 消费者重要参数 bootstrap.servers 向 Kafka 集群建立初…

Jackson使用进阶

实现 注解 属性命名 JsonProperty 定义属性序列化时的名称。 JacksonAnnotation public interface JsonProperty {public final static String USE_DEFAULT_NAME "";public final static int INDEX_UNKNOWN -1;//指定属性的名称。String value() default USE_…

2022IDEA搭建springMvc项目

springmvc项目搭建一. 创建maven项目二. Add Framework Support三. 添加依赖并配置maven四. 配置前端控制器DispatcherServlet五. 配置SpringMVC.XML文件六. 创建controller类七. 创建index.html页面八. 查看jar包是否添加九. 配置tomcat&#xff08;重&#xff09;十. springm…

Kafka(7):生产者详解

1 消息发送 1.1 Kafka Java客户端数据生产流程解析 1 首先要构造一个 ProducerRecord 对象,该对象可以声明主题Topic、分区Partition、键 Key以及值 Value,主题和值是必须要声明的,分区和键可以不用指定。 2 调用send() 方法进行消息发送。 3 因为消息要到网络上进行传输…

国产蓝牙耳机什么便宜又好用?学生党平价蓝牙耳机推荐

蓝牙耳机凭借近几年的快速发展&#xff0c;越来越多的品牌、款式出现在人们的日常生活当中。最近看到很多人问&#xff0c;国产蓝牙耳机什么便宜又好用&#xff1f;针对这个问题&#xff0c;我来给大家推荐几款平价蓝牙耳机&#xff0c;很适合学生党&#xff0c;一起来看看吧。…

推荐系统从入门到入门(3)——基于MapReuduce与Spark的分布式推荐系统构建

本系列博客总结了不同框架、不同算法、不同界面的推荐系统&#xff0c;完整阅读需要大量时间&#xff08;又臭又长&#xff09;&#xff0c;建议根据目录选择需要的内容查看&#xff0c;欢迎讨论与指出问题。 目录 系列文章梗概 系列文章目录 三、MapReduce 1.MapReduce详…

赶紧收藏:如何使用Telegram客户支持

想要使用Telegram需要客户支持&#xff1f;您需要了解的有关使用Telegram作为客户服务渠道的所有信息&#xff0c;本文章都会介绍。我们将首先讨论提供Telegram支持以及入门所需了解的内容。然后&#xff0c;我们将向您展示如何用智能客服工具ss可以帮助您提供一流的服务Telegr…

Oracle监听详解

本文摘自《ORACLE数据库技术实用详解》和《成功之路&#xff1a;ORACLE 11g学习笔记》 配置网络环境 本文将介绍和Oracle相关的网络问题&#xff0c;Oracle网络建立在操作系统之上。配置操作系统网络是配置Oracle网络的第一步。在配置Oracle网络之前&#xff0c;我们需要确保操…

数学基础--均值、方差、标准差、协方差

1. 简介 统计学中最核心的概念之一是&#xff1a;标准差及其与其他统计量&#xff08;如方差和均值&#xff09;之间的关系&#xff0c;本文将对标准差这一概念提供直观的视觉解释&#xff0c;在文章的最后我们将会介绍协方差的概念。 2. 概念介绍 均值 均值&#xff1a; 均值…

(一)Spring-Cloud源码分析之核心流程关系及springcloud与springboot包区别(新)

文章目录1. 前言2. springcloud简介3. Springcloud包简介4. Springcloud和Springboot流程关系5. Springcloud启动流程新增的功能和接口5.1 新增接口5.2 新增功能类5.2.1 spring-cloud-context包5.2.2 spring-cloud-commons包6. Springcloud实现机制带来的问题7. Springcloud和S…

【MyBatis】映射器配置|注解完成CRUD(三)

&#x1f697;MyBatis学习第三站~ &#x1f6a9;起始站&#xff1a;MyBatis概述&环境搭建(一) &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 &#x1f44d;希望您能有所收获 上一篇我们学习了如何使用Mapper代理开发&#xff0c;核心配置文件&#xff0c;但却…

OnlyOffice验证(一)DocumentServer编译验证

OnlyOffice验证&#xff08;一&#xff09;DocumentServer编译验证 资源准备 Ubuntu16.04桌面版 验证用的版本[ubuntu-16机接上传ubuntu.04.7-desktop-amd67131.iso&#xff0c;&#xff08;别用高版本&#xff01;试过20.04耽误两三天&#xff0c;差点放弃了&#xff09;&am…

javaee之node.js与es6

问题1&#xff1a;在IDEA控制台为什么node显示不会出来命令 修改完之后记得重新启动电脑 问题2&#xff1a;response.end()作用 在Web开发中&#xff0c;浏览器端的请求到达服务器进行处理的时候&#xff0c;Response.End的作用就是让request执行到此结束&#xff0c;输出到客户…

移掉K位数字-力扣402-java贪心策略

一、题目描述给你一个以字符串表示的非负整数 num 和一个整数 k &#xff0c;移除这个数中的 k 位数字&#xff0c;使得剩下的数字最小。请你以字符串形式返回这个最小的数字。示例 1 &#xff1a;输入&#xff1a;num "1432219", k 3输出&#xff1a;"1219&q…

Vue实战第5章:发布Vue工程到github静态页面

前言 本篇在讲什么 简单讲解关于Vue发布github静态页面相关的内容 本篇适合什么 适合初学Vue的小白 适合想要自己搭建网站的新手 本篇需要什么 对Html和css语法有简单认知 对Vue有简单认知 Node.js(博主v18.13.0)的开发环境 Npm(博主v8.19.3)的开发环境 Vue(博主v5.…

< elementUI组件样式及功能补全: 实现点击steps组件跳转对应步骤 >

文章目录&#x1f449; 前言&#x1f449; 一、效果演示&#x1f449; 二、点击steps跳转效果实现&#x1f449; 三、实现案例往期内容 &#x1f4a8;&#x1f449; 前言 在 Vue elementUi 开发中&#xff0c;elementUI中steps步骤条组件只提供了change方法&#xff0c;并未提…

【Database-03】从 MySQL 迁移到 达梦数据库(DM 8)

1、环境 源数据库 MySQL 8.30 目标数据库 DM 8 操作系统 Centos 9 Steam 迁移工具 DM 数据迁移工具 (DM DTS) 2、开始迁移 2.1、打开DM数据迁移工具 在新建工程对话框中填写工程名和工程描述信息&#xff0c;点击【确定】按钮&#xff0c;成功添加了一个工程。 2.2、新建迁…

海思SD3403/SS928V100开发(5)MIPI_YUV相机vio sample开发----修改思路

1. 前言 sensor输出格式: YUV422 8bit 硬件连接: MIPI_YUV相机(4lane MIPI) -> SS928V100 MIPI0(4lane) 框图: 2. 几个问题 基于SS928 SDK中的 vio sample修改; 但是sample里面都是基于RAW RGB sensor开发的sample, 没有现成的MIPI_YUV sensor的参考,需要自己…

[黑马程序员SSM框架教程] Spring-11-setter注入

思考&#xff1a;向一个类中传递数据要几种&#xff1f; set方法构造方法 思考&#xff1a;依赖注入描述了在容器中建立bean与bean之间依赖关系的过程&#xff0c;如果bean运行需要数字或字符呢 引用类型简单类型&#xff08;基本数据类型和字符串&#xff09; 注入方式&#x…

软考学习笔记(题目知识记录) 2023.2.24

答案为 概要设计阶段 本题涉及软件工程的概念 软件工程的任务是基于需求分析的结果建立各种设计模型&#xff0c;给出问题的解决方案 软件设计可以分为两个阶段&#xff1a; 概要设计阶段和详细设计阶段 结构化设计方法中&#xff0c;概要设计阶段进行软件体系结构的设计&…