Iframe嵌入--关于onload与document.domain

原标题:Iframe, onload 与 document.domain web2.0 时代,网站开发人员开始关注将第三方网页的内容嵌入自己的网页中(使用iframe元素)。 o_z71@6-tYy!$rF7CEjgN iframe 和 javascript 对象的所有权 当javascript能够通过其域名进行数据交互后,iframe开始提供一系列的安全措施,使得一个嵌套于iframe中的第三方网站不可能获取到主体网站的脚本程序。这个跨域的限制同样也让父级页面无法读取嵌套内容的脚本。 Mr.W3C - 设计师、开发师、站长必上的网站。 从所有权的角度来说,父级页面和被iframe包含的页面是完全没有联系的。这个复杂的关系让javascript对象的所有权成为了许多有关iframe讨论的话题之一。 }ut5@r3iyOE[44rdT iframe元素本身是位于父级页面中的,所以你可以像一个普通元素一样的使用和操作它。代表了iframe内容window对象是作为一个页面的属性加入到iframe中的。为了让父级页面能够以一 种合适的方式获取iframe的window对象,父级页面和iframe页面的域名应该保持一致(参考:About Cross-Frame Scripting and Security)。 www.mrw3c.com,专业的网页设计知识库。 当名吻合时,父级页面就可以获取iframe的window对象了。iframe元素拥有名为contentDocument的属性,这个属性包含了iframe对象的 document对象,于是我们就可以使用parentWindow这个属性取回window对象。这已经成为了获取iframe的window对象的标 准方法,并被绝大多数浏览器支持。ie8以前的浏览器不支持这个属性,我们需要用以使用其专有的contentWindow属性。如 ]t0-N.73R:B21vjwWl function getIframeWindow(iframeElement){ return iframeElement.contentWindow || iframeElement.contentDocument.parentWindow; } �功能应用。 补充一点,父级页面的window对象在iframe中能够以window.parent获取。iframe元素同样也可以使用 window.frameElement来获取自己的引用。由于iframe被父级元素包含但却可以直接获取到iframe的window对象,该方法广 泛用于突破二者的界限。 iframe元素的onload事件 由于各种所有权的不同,尝试确定iframe何时装载完毕是一个很有趣的实验。非ie浏览器提供了许多有用的方法。它们让iframe元素拥有 load事件,这样我们就可以确定iframe何时装载完 全。由于iframe元素包含于父级页面中,你也不用担心跨域的限制。装载本地数据的iframe可以使用监听装载外部数据的iframe完成事件的相同 方法。举例如下: @4:,WM$xV#e var iframe = document.createElement("iframe"); iframe.src = "simpleinner.htm"; iframe.onload = function(){ alert("Iframe is now loaded."); }; document.body.appendChild(iframe); y~P(}enl( !. 上面的例子在所有非ie浏览器中均适用。我曾经尝试使用attachEvent方法,不过最终发现ie并不支持在iframe上的load事件。 Z!pNrUjT}3Q061M=2#SfJ==* iframe的window对象的onload事件 看起来ie又要给我们制造难题了。不过随后,我记起来我以前没有考虑过在iframe中引用外部文件。在我的实验中,我曾经处理了同一域名下的内容。由于跨域限制不存在,我能够轻易的获取iframe对象的window对象并加上onload事件。例如: y~P(}enl( !. var iframe = document.createElement("iframe"),iframeWindow; iframe.src = "simpleinner.htm"; document.body.appendChild(iframe); iframeWindow = iframe.contentWindow || iframe.contentDocument.parentWindow; iframeWindow.onload = function(){ alert("Local iframe is now loaded."); }; 站长关注,关注站长需要关注的,助力个人站长的发展。 有 趣的是,你必须在iframe元素已经加到页面中以后才能注册事件。如果先于它,iframe的window对象将不存在,我们也当然不可能在 window对象上注册事件。这个方法只在ie和ff下对于同域的两个嵌套页面有效。其他浏览器不会创建window对象并将抛出异常。 7wjV_p0~.]gVXW+L(L 定义document.domain 我 试图寻找一种可以监听ie里iframe的load事件的方法以及更多的应用于其他浏览器的方法,于是我继续了我的实验。接下来,由于我有多个需要使用 iframe读取的不同二级域名的页面,我设置了父级页面的document.domain。将document.domain设定为主域名能够允许这些 iframe之间以及同父级页面的通信。例如,如果我有需要读取一个地址为www2.nczonline.net的iframe,在技术上上说是不被允许 的。不过,如果我在父级页面和iframe页面中均设置了document.domain为'nczonline.net',这两个页面将可以相互通讯。 如下: document.domain = "nczonline.net"; 这个声明消除了域名的区别,我们可以像处理两个相同域名的网站一样处理这两个页面。 有 一个问题又产生了。在iframe完全加载前,它将被认为是属于iframe标签中声明的src属性标志的页面的。相对地址被自动加上了父级页面的地址 (www.nczonline.net)并与我们设置的document.domain相矛盾。这意味着在比较nczonline.net和 www.nczonline.net时,我们将通不过同域检查,于是当我们试图获取iframe的window对象时,将引起javascript的报 错。iframe页面并不会改变其关联的domain值,直到它加载完毕,届时改变domain值的脚本才会执行。当iframe已经加载完毕时,一切运 行完美。但是,我们是怎么知道iframe什么时候才加载完? o_z71@6-tYy!$rF7CEjgN 转变一下想法 由于一致没有找到一种可以跨浏览器解决判定iframe是否加载完毕的方法,我决定转变一下我的想法。如果我们让iframe告诉父级页面它已经加载完毕,而不是让父级页面去获取iframe 的load事件,也许能够解决问题。我希望这种方法能够与注册一个事件句柄一样简单,所以我采用了下面的想法:我在iframe元素上声明一个方法,然 后,当iframe页面加载完毕之后会执行这个函数。当然,这个方法是被声明到iframe元素本身而不是iframe的window对象上的,后一方法 在前面的研究中被证明不能兼容所有的浏览器。结果看起来像这样: @4:,WM$xV#e var iframe = document.createElement("iframe"); iframe.src = "simpleinner.htm"; iframe._myMethod = function(){ alert("Local iframe is now loaded."); }; document.body.appendChild(iframe); qWU4D08)DF@=,JvJ[(UH1owo 上面的代码在iframe元素上声明了_myMethod的方法。iframe中的页面加入如下方法: window.onload = function(){window.frameElement._myMethod();} ]t0-N.73R:B21vjwWl 由于上述代码是在我们声明document.domain之后运行的,于是我们便不用担心任何安全限制的问题。这种方法在同一主域名下工作得很完美。它能够兼容所有的浏览器,这也正是我所需要的。但是,监听包含第三方页面的iframe的load事件仍然在困扰我。 iframe的onreadystatechange 我决定研究一下ie浏览器关于iframe的接口文档。如果在onload事件中声明某些事件显而易见不能达到我们想要的效果,但是我觉得肯定会有类似的方 法。我尝试使用attachEvent方法去增加事件句柄,但是仍然没有用。ok,显然ie中的iframe并不支持load事件。有其他方法吗? # Lj:erb1pFf 接下来我使用了ie的一种怪异的方法——readystatechange事件。显然它与xhr对象的readystatechange事件完全不一样。我 想知道是否iframe元素也支持这个事件,它会在iframe嵌套的内容加载完全前变成'interactive',随后变成'complete'。同 时,由于它是注册到iframe元素而不是iframe的window对象上,这理所当然不会存在跨域的问题。最后我整理出来的代码如下: q]{,UneT]PmMpU var iframe = document.createElement("iframe"); iframe.src = "simpleinner.htm"; if (navigator.userAgent.indexOf("MSIE") > -1 && !window.opera){ iframe.onreadystatechange = function(){ if (iframe.readyState == "complete"){ alert("Local iframe is now loaded."); } }; } else { iframe.onload = function(){ alert("Local iframe is now loaded."); }; } document.body.appendChild(iframe); $3S::N?NK}clnSdEKY5A 判断浏览器是否为ie浏览器稍稍有些麻烦。本来我更偏向使用判断iframe.readystate是否存在来进行浏览器的检测。但是,当试图获取未加入到 页面中的iframe的属性时会抛出一个错误。我也尝试使用document.readyState去判断是否使用readystatechange,然 而,已经有很多浏览器支持前一属性了,所以它并不是一个有效的划分手段。 ie 对onload事件的支持 在发表这 篇文章后短暂的时间里, Christopher留言说在iframe元素上使用attachEvent是能够在ie下工作的。我发誓我之前已经尝试过这样的方法,但是由于他的提 示,我尝试了另外一个实验。随后发现,他是正确的。随后我研读了msdn上的文档,最后终于发现了一段文档说明了这个问题。它最终让我们的代码变成了下面 这个样子 编程开发,网站编程与开发,网站后台功能实现。 var iframe = document.createElement("iframe"); iframe.src = "simpleinner.htm"; if (iframe.attachEvent){ iframe.attachEvent("onload", function(){ alert("Local iframe is now loaded."); }); } else { iframe.onload = function(){ alert("Local iframe is now loaded."); }; } document.body.appendChild(iframe); "0-J #APLYFy]aPdD6TC@f7uK= 以上的代码仍然能正常运行于所有的浏览器之上,并能回避readystatechange事件与load事件潜在的冲突可能。 www.mrw3c.com,专业的网页设计知识库。 综述 ~]~x@}FyBT]TGmgF:HN]2Ml0J 在 一小段调研之后,我们发现确定一个iframe对象何时加载完成的跨浏览器的方法是存在的。这让我们对iframe的监听和错误控制变得容易的多。感谢所 有的浏览器厂商看到了在iframe元素上添加这些事件的好处,而不是去依赖iframe的window对象或者认为我们平时并不关心iframe何时完 成加载。 5Jgf$}Wd/t8] 原文:http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/ v)#0E@dOFk#J6!_GenkkeO)Utm 译文:http://www.cnblogs.com/demix/ www.mrw3c.com,专业的网页设计知识库。 译者:Demix
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这段代码可以进行如下的优化: 1. 避免在函数内部操作 DOM,最好将其作为参数传递进来,这样可以提高代码的可重用性和可维护性。 ```javascript const print = (elId, cssUrl) => { const el = document.getElementById(elId) if (!el) { message.error("找不到打印内容,请检查elId") return } if (!baseInfo.orderCode) { message.error("打印正在准备,请5秒后再点击") return } const iframe = document.createElement("IFRAME") document.body.appendChild(iframe) const doc = iframe.contentWindow.document doc.write(`<LINK rel="stylesheet" type="text/css" href="${cssUrl}">`) doc.write(el.innerHTML) doc.close() iframe.contentWindow.focus() iframe.onload = () => { iframe.contentWindow.print() document.body.removeChild(iframe) } if (navigator.userAgent.indexOf("MSIE") > 0) { document.body.removeChild(iframe) } } ``` 2. 将打印的专有CSS样式和打印的内容分开处理,以便更好地维护和修改样式。 ```javascript const print = (elId, cssUrl, printContent) => { const el = document.getElementById(elId) if (!el) { message.error("找不到打印内容,请检查elId") return } if (!baseInfo.orderCode) { message.error("打印正在准备,请5秒后再点击") return } const iframe = document.createElement("IFRAME") document.body.appendChild(iframe) const doc = iframe.contentWindow.document const link = document.createElement("link") link.rel = "stylesheet" link.type = "text/css" link.href = cssUrl doc.head.appendChild(link) doc.body.innerHTML = printContent || el.innerHTML iframe.contentWindow.focus() iframe.onload = () => { iframe.contentWindow.print() document.body.removeChild(iframe) } if (navigator.userAgent.indexOf("MSIE") > 0) { document.body.removeChild(iframe) } } ``` 3. 将打印内容从 DOM 中分离出来,以便在不同的场合下方便地调用。 ```javascript const printContent = (elId) => { const el = document.getElementById(elId) if (!el) { message.error("找不到打印内容,请检查elId") return "" } return el.innerHTML } const print = (elId, cssUrl, printContent) => { if (!baseInfo.orderCode) { message.error("打印正在准备,请5秒后再点击") return } const iframe = document.createElement("IFRAME") document.body.appendChild(iframe) const doc = iframe.contentWindow.document const link = document.createElement("link") link.rel = "stylesheet" link.type = "text/css" link.href = cssUrl doc.head.appendChild(link) doc.body.innerHTML = printContent || printContent(elId) iframe.contentWindow.focus() iframe.onload = () => { iframe.contentWindow.print() document.body.removeChild(iframe) } if (navigator.userAgent.indexOf("MSIE") > 0) { document.body.removeChild(iframe) } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值