先看一下我们遇到了什么问题? 在我们的白社会里,需要嵌入第三方应用,而嵌入的方式是使用iframe,为了页面美观,这里就有一个最简单的需求:iframe的高度需要跟随其本身内容的变化而实时变化,这就要求主页面根据iframe的内容实时的去设置其样式height值,但是因为第三方应用和白社会不属于同一个域,所以给实现带来了一点小小的麻烦,所以才有以下的一些讨论 仔细分析一下问题的实质是什么呢? 其实这里需要解决的是,在一个页面A中嵌入一个iframe名字叫B,A和B不属于同一个域,但是A和B需要进行一些必要的通信,传递少量的数据信息,所以问题的实质就是主页面与跨域iframe之间怎么通信,也就是怎么传递数据信息 下面就针对两种不同的需求,总结一些比较简单,常用和稳定的解决方案。 主页面A怎么向iframeB传递数据 iframeB怎么与主页面A传递数据 需求一:主页面A与iframeB的怎么传数据呢? 这种方式,是主页面需要给iframeB传递数据,然后iframeB获得到数据后进行特定的处理 实现方式 实现的技巧就是利用location对象的hash值,通过它传递通信数据,我们只需要在主页面A中设置iframeB的src后面多加个data字符串(data就是你要传递的数据),如下图所示: 然后在iframeB中通过某种方式能即时的获取到这儿data就可以了,其实常用的一种方式就是: 1。在iframeB中通过setInterval方法设置定时器,监听location。href的变化即可获得上面的data信息 2。然后iframeB就能根据这个data信息进行相应的逻辑处理 需求二:iframeB与主页面A的又怎么传数据呢? 这种方式,是iframeB需要给主页面传递数据,然后主页面根据获得到数据后进行特定的处理 实现方式 实现的技巧就是利用一个代理IframeC,它嵌入到iframeB中,并且和主页面A必须保持是同域,然后我们通过它充分利用上面第一种通信方式的实现原理就能把iframeB的数据传递给iframeC,接下来的问题就是怎么让iframeC把数据传递给主页面A,如下图所示: 因为,iframeC和主页面是同域的,所以它们之间传递数据就变得简单多了,我们这里的方式就是使用一个经常使用的属性window。top(也可以使用window。parent。parent),它返回对载入浏览器得最顶层window对象的引用,这样我们就能直接条用主页面A中方法啦,哈哈哈,简单吧。 到此,我们做个简单分析总结 当然还有其他一些方式,也都测试过,不是浏览器兼容性不好,就是实现起来复杂,通过以上方式就能很方便的在跨域的iframe和主页面之间传递数据了,当然也就能解决上面提到的设置iframe高度的问题了,但是这种实现方式的前提也是最大的缺点就是iframe中的内容必须是我们可控的,但是至少我们这种实现方式是建立在浏览器的安全规则之上的,没有破坏应用本身的安全性。 进一步叨叨,实现时需要考虑的一些细节 上面的分析,其实只是一个简单的原理,在白社会里,虽然我们目前的需求还仅仅是实现第三方iframe形式的App的高度自适应,但是我们在实现的时候尽量考虑到了易用,可扩展性和可维护性,比如: 让第三方App只需加载一个我们提供的JS种子文件就能很方便的使用我们为其提供的各种工具 上面的各种工具,我们采用包的形式进行组织,最大化的实现按需加载 第一条中的JS种子文件只提供基础的方法实现,并且把最常用的工具包放在里面,比如高度自适应 通过种子文件,我们还提供给第三方App一些常用的JS工具包,而且直接使用的类似YUI3模块的动态加载机制就可使用指定的工具包 对第三方App和主页面传递的数据进行分类(自我调用,登录验证,传递数据等等) 传递的数据使用满足特定规范的JSON格式,并通过统一的服务出口发出去,主页面提供一个统一服务接口解析数据,并根据规范调用相应的方法 还有,就是版本控制的问题,为了尽量减少给第三方App带来影响,以上所有这些JS文件的版本都是采用向后兼容的策略,小版本使用服务器设置SQUID缓存特定频率的实效时间实现,大版本更新根据用户自己的需求手动更改 当然,以上可能不是最优的解决方案,只是希望能给你一些帮助和引导,我们也在逐步的改进我们的一些实现方式,比如版本控制这块儿,我们也有一些问题需要解决 回过头来,我们再看点儿具体的代码 主页面A的源码 主页面A 主页面A functioninit(){ document。domain‘bai。sohu。com’; alert(‘我是主框架,里面嵌入第三方应用的IframeB,下面开始加载第三方应用’); variframeTagdocument。getElementById(‘frameB’), iframeSrc‘http:10。10。92。117testspringwangCrossDomainautoSetHeightiframePage。html’; iframeTag。srciframeS iframeTag。style。display‘block’; }; functioncallback(h){ variframeBdocument。getElementById(‘frameB’); alert(‘IframeC调用我(主框架)接口,把IframeB的高度传给我,具体值是:’h); iframeB。style。heighth10‘px’; iframeB。src‘’h }; 我是主页框架,我的域是:bai。sohu。com iframeB(iframePage。html)的源码 iframeB 我是三方应用,我的域是:10。10。92。117 functioninit(){ alert(‘我是第三方应用,下面开始创建和主框架同域的通信通道IframC,并设置它的src,用号传递高度值’); variframeTagdocument。getElementById(‘frameC’), iframeSrc‘http:bai。sohu。comtestspringwangCrossDomainautoSetHeightiframePageC。html’, pageHeightdocument。documentElement。scrollHeightdocument。body。scrollH iframeTag。srciframeSrcpageH iframeTag。style。display‘block’; window。setTimeout(function(){ alert(‘主页面设置我(IframeB)的src,通过Hash()给我传递它收到的高度:’location。hash); },2000); }; iframeC(iframePageC。html)的源码