js自定义消息机制研究学习

来源:互联网 发布:linux压缩包命令 编辑:程序博客网 时间:2024/06/05 02:44

网址:http://www.cnblogs.com/ozdoo/archive/2011/09/01/2161936.html

iframe通信机制
 
关于iframe的通信也许我的实践不是最佳实践,我知道yahoo在这方面的研究是比较深入的,当初ajax兴起之时,yahoo邮箱是基于大量的iframe完成的。但是我没有研究过,你可以看看他们的代码。
 
我这里的iframe通信主要是指同域iframe与父窗口,同级iframe之间互传消息。
 
附件有一个实现及示例(请看iframe.html),同样还是基于monitor对象
简单描述一下:
 
我设置一个顶级对象:delivery用于处理iframe之间的通信
他有两个方法:
parent:获得父窗口的delivery对象
pipeline:管道,负责投递同级iframe之间的信息
 
目前我写了一个临时的pipeline处理(delivery.bind("pipeline",function…… 在iframe.js中),是根据iframe的name属性匹配的,具体到应用的时候,可以根据你自己的需求定制,比如根据iframe内页面的title,href等等进行匹配
 
我觉得这样做的好处:
1. 易于单页面调试,parent,pipeline的调用不会因为指定窗口的不存在而弹出错误,parent函数在父窗口不存在的情况下会创建一个新的delivery实例
 
2. 消息(事件or数据,看你怎么定义)传递出去,页面js 的任务就结束,降低了页面之间的依赖。比如pipeline并不会因为指定的iframe页面不存在就影响下边的js执行
   像层级架构,父页面(或目标页)不需要知道iframe子页面(或要调用它的页面)是否存在,他只提供消息处理(就像一个接口)。
 
3. 单一消息口,使用delivery一个对象来处理所有从其他页面传过来的消息。降低了复杂度,以前有一些做法是写一些函数,或者定义一些变量,由要调用的页面来操作,这样增加了很多的页面依赖及复杂度。
 
 
当然,它页有一些弊端,比如回调,比如单一的delivery需要注意消息名称冲突等等

(附代码:)
View Code




邮件摘录二:
由于是工作时间,我只能简单看了下你的代码。提一些个人的见解:
我看到了两行代码
parent.document.getElementById("Tli_brainpower").style.display="none";
parent.IFrameReturnValue(thiss.getTds());
网上有很多文章教我们这么做,这也是一个基本的iframe调用方式,相类似的还有直接修改某一公用变量值,如parent.xxxx=0等等
在一些很简单的页面中,我不反对这么做(偷懒的时候我也这么干)
 
但这里有一些风险:
1. 直接操作了父页面元素,这首先造成一种强制,父页面必须有这个元素,比如上面的代码id为Tli_brainpower的dom、IFrameReturnValue函数,在父页面必须存在,否则程序无法运行。这肯定限制了父页面的改动。
你在改动这个页面的时候,你得不停的关心你会调用那些iframe页面,而内部的iframe页面又引用哪些元素等等。结果就是,你改了一个id,它就会留下一个隐患,让你的程序崩掉。
当只有你一个人操作这套程序的时候,也许记性会帮你(但用处也不大,我就是一个善忘的人),但当很多人和你一起开发,有UI帮你调整页面,甚至你会被要求改版等等……
简单来说,只要你有改动,你就会很痛苦。
 
 
2. 混乱的调用,直接调用的方式潜在的允许,你的iframe内的页面可以操作所有页面元素,同时,我们也许会出现要调用很多不同的iframe页面,他们又要实现很多相同或不同的对父页面的操作。
也许是这样的,iframe1要修改div1 div2 div3 div4的样式,同时它会调用fun1 fun2 fun3 fun4的父页面函数,iframe2要修改div5 div6 div7 div8的样式,同时它会调用fun5 fun6 fun7 fun8的父页面函数。
有时,我们还要iframe1调用一些iframe2的数据(我们这边现在就有这样的需求,两个iframe页面间大量数据交互)
最终,他们是一个网状结构,要维护他们,或者要看懂他们你需要花费很多的精力和时间(之前维护过一个系统,他的调用是parent.parent.frames,frames["main"].frames[""]遍布页面。很让人郁闷)
 
 
parent.很便利,但是不建议在页面里大量使用这种方式。我们用编程中高内聚低耦合的观点来设计这些页面交互。
 
我们换一种思路来考虑问题,把每一个页面当做是独立体、一个对象。
如果把一个页面当做是对象,那么一个对象是有自己属性,自己方法的一个独立体。
比如这样形容:
index页面:setMember()设置会员  addRow()添加一行数据 
iframe1页面(会员选择iframe页面):selectMember()选中会员
iframe2页面(数据选择):selectData()选中数据
这样就比较清晰了
这里,我们首先要实现页面的内聚,简单来说,对于这个页面元素的控制只允许本页面(当然包括它所引用的js代码)自己来控制。我们可以把所有页面元素(实际上也包括存在js中的数据)当做是私有的,决不允许其他页面代码直接控制,这样来提高页面js代码的聚合性。
parent.document这样代码会让对index这个页面操作代码散落各处,违背了高内聚的准则,最好封装成一个方法供别的页面调用。
 
 
 
接下来讨论一下页面间的低耦合
假设在index里用iframe调用了iframe1,iframe2页面,那么调用方式是这样的:
iframe1:
    var member=selectMember();
    parent.setMember(member);
iframe2:
    var data=selectData();
    parent.addRow(data);
这是一种直接的方案,虽然比直接操作父窗口元素、数据耦合度低,但耦合度依然较高。
用一个词来形容:“依赖”,他造成iframe1、iframe2的依赖于index(或者说依赖于具有setMember,addRow方法的页面)
也许我们那天要再写一个页面index2,要用到iframe1,iframe2,那么我们必须按照调用写setMember,addRow
但是index2实际上要执行的是deleteMember,deleteData呢?
 
如何解除依赖(或者降低依赖)?
一些设计原则教我们,面对频繁变动的需求、代码,我们开发的东西最好依赖于稳定的对象(依赖于抽象、依赖于接口),而不是依赖于频繁变化的东西(比如变量,固定的方法,这里包括父窗口的dom元素)
之前我写的示例中:delivery就是比较稳定的一个对象(只有在开发前期我们会好好设计并修改它)。
 
 
那么以delivery的模式来解除依赖的关系,如:
iframe1:
    selectMember(){……  delivery.parent.trigger({type:"selectMember",member:member}) }
iframe2:
    selectData(){……  delivery.parent.trigger({type:"selectData",data:data}) }
当然它也有依赖,比如依赖于我示例写的delivery对象,但是只依赖于一个对象(且是全局统一的一个对象),要好于直接依赖于方法名(尤其是当你需要调用多个方法名的时候或不确定方法名得时候)。
那么主页面就会如下:
index:
    delivery.bind("selectMember",function(data){ setMember(data.memeber) })
index1:
    delivery.bind("selectMember",function(data){ deleteMember(data.memeber) })
 
 
通过委托delivery对象负责传递数据,子页面不再关心父页面做什么,父页面也不关心,是谁触发的selectMember(因为你可以在当前页面内用delivery.trigger触发调用,而不是通过iframe内的页面来触发)
大多时候,他们并不感知iframe、parent页面的存在,他们只与稳定的delivery对象打交道。他们之间的耦合降低了
所有的页面依赖于功能稳定的delivery对象,而不是一个不知谁开发、不知何时调用、不知有什么内容的一个页面(或js)
 
 
 
 
 
高内聚低耦合的准则适用很多场景,记住这个基本准则并应用可以良好的解决很多问题。比如有很多页面的时候,我们要像设计面向对象那样设计页面的职能,抽象它的行为。
 
 
delivery的模式也许在初期会带来很多麻烦和困扰,比如iframe1发了信息,index却没有正确处理。
这是因为原来直接的setMember调用,修改成了复杂的bind ,trigger-》function-》setMember模式,中间环节只要有一点问题,数据就无法准确抵达。
复杂的方式是应对复杂的问题,复杂的方式也会带来一点性能损伤,具体要根据你的需求来决定。
 
三种方案:
1.parent.domcument  parent.xxx(变量)   使用iframe很少发生交互的情况下使用,比如几百个页面,偶尔一个页面有这个需求,我们就不必大费周章用什么模式了。
2.parent.fun        少数页面,交互只涉及很少几个函数。
3.delivery          很多的页面、很多的交互。依赖于稳定的对象(比如delivery),要好于直接依赖于变化多端的页面及js代码。






原创粉丝点击