多处 iframe 的通信

分享 已结 置顶 精帖 21 5679
匿名丶
匿名丶 2020-5-3
悬赏:20飞吻
一、引子

今天浏览帖子,发现一个提问: top open的子窗口怎么向父窗口传值 ,当然问题已经解决了。原先我打算说些我的想法,但是人家来解决问题,我在下面侃侃而谈也不太好。

所以我就起了个帖子,谈谈我自己在处理此类问题的想法。也许有些理解偏差,如果有还请回复或者私信我修改过来,防止误人。

需要注意下:肯定是包含 iframe 的,即单页不考虑。


二、问题点

简单说就是“高耦合”,通常我们处理,都是找到相应的那一层,在调用其方法,即parent[1...n].funcName() 来处理(当然有些手段不一样,当时无外乎需要 ' parent ' 和 ' 方法名 ' 的调用)。

假设突然某一天父层的方法名因为一些原因([嘘] )被修改了,那么一连锁的子层都是报错。这样看来,这类子层高依赖父层的耦合代码就像一个定时炸弹。


三、寻找解决方法

既然问题找到了,那么我们只要解决这个高耦合就好了。

3.1 第一个方案

网上推荐的 iframe + postMessage 来实现网络通信,我也尝试了这么做,也成功了。可惜项目需要兼容 ie8,这就相当尴尬了,无情 pass [失望]

3.2 理想的处理方式

在经过一段时间后,因为在做另一个项目,使用了 vue ,发现 vue 中在处理组件问题使用 $emit 与 $on 来通信就特别简单,这又让我联想到如果我将每一个 iframe 当成组件,

也如此这般使用,那不是很简单,可惜知识储备力不足,被我搁置了,仍使用老方法。

3.3 转机

偶然机会,在社区看到了一个帖子:探索 layui 的 onevent 和 event ,这里面介绍了 layui.event 和 layui.onevent 。

从帖子里面我发现了 layui.event 和 layui.onevent 有点像 vue 中的 $emit 和 $on 的简易版。

通过测试验证了我的想法,那解决方法也就找到了 [嘻嘻]


四、简单的 DEMO

通常我们的每个页面会引用一些全局脚本,那么在这个全局脚本中,我们可以加入以下代码:

假如 common.js 模块是全局脚本
layui.define([], function(exports) {
// 我们需要将此方法使用顶层 layui
// 这样可以确保每个子层都可以使用
// 我们需要获取顶层 layui 对象
var MODULE_NAME = 'common'
var isTop = top === self
var _layui = isTop ? layui : top.layui

var common= {
// 事件监听
$on: function(eventType, callback) {
return _layui.onevent.call(this, MODULE_NAME, eventType, callback)
},

// 事件响应
$emit: function(eventType, params) {
_layui.event.call(this, MODULE_NAME, eventType, params)
}
}

exports(MODULE_NAME, common)
})
父级页面(father.html):
// html
<div class="father" style="width: 400px; padding: 2em; background-color: #ccc;">
father
<input id="lay-input">
<p id="lay-output" style="background-color: #fff; margin-top: 10px; min-height: 50px;"></p>
<iframe src="children.html" style="margin-top: 10px; border: 2px solid"></iframe>
</div>

// js
layui.use(['jquery', 'common'], function($, common) {
var message

$('#lay-input').on('input', function() {
message = $(this).val()
common.$emit('on-father', { message: 'from father: ' + message })
})

common.$on('on-children', function(data) {
$('#lay-output').html(data.message)
})
})
子级页面(children.html):
// html
<div class="children" style="padding: 2em;">
chilren
<input id="lay-input">
<div id="lay-output" style="background-color: #fff; margin-top: 10px; min-height: 50px;"></div>
</div>

// js
layui.use(['jquery', 'common'], function($, common) {
var message

$('#lay-input').on('input', function() {
message = $(this).val()
common.$emit('on-children', { message: 'from children: ' + message })
})

common.$on('on-father', function(data) {
$('#lay-output').html(data.message)
})
})
效果也是妥妥的:


一路偷偷粘贴复制代码,终于是完成了[嘻嘻]

- EOF -

四、感想

以往都是用轮子,真的设计原理不曾花时间研究下,这种类似观察者和订阅者关系的模式,在 vue 中常有,不曾想 layui 中也有。[good]

然后又是发现一个新的名称:响应式编程(可能有落伍了),就像新大陆一样 [偷笑]

真是越学越觉得自己什么都不会,哈哈 ~~

回帖