
概述
HTML 内联框架元素 (<iframe>) 表示嵌套的 browsing context。它能够将另一个 HTML 页面嵌入到当前页面中。
简单尝试
<h2>嵌入一个站点</h2>
<iframe
id="inlineFrameExample"
title="Inline Frame Example"
width="300"
height="200"
src="https://www.ip.top/"
></iframe>

每个嵌入的浏览上下文(embedded browsing context)都有自己的会话历史记录 (session history)和 DOM 树。包含嵌入内容的浏览上下文称为父级浏览上下文。
顶级浏览上下文(没有父级)通常是由 Window 对象表示的浏览器窗口。
【注意】iframe 性能问题考虑
页面上的每个 <iframe> 都需要增加内存和其他计算资源,这是因为每个浏览上下文都拥有完整的文档环境。虽然理论上来说你能够在代码中写出来无限多的<iframe>,但是你最好还是先看看这么做会不会导致某些性能问题。
属性
全局属性
width
【属性-作用】指定 iframe 的宽度。
【值】
- 无单位数值; (默认值) 300,例如:500
- CSS 像素格式;例如: 300px
- 百分比格式;例如:33%
height
【属性-作用】指定 iframe 的高度。
【值】同上
name
【属性-作用】 用于定位嵌入的浏览上下文的名称。
该名称可以用作 <a> 与 <form> 的 target 属性值,
该名称可以用作 <input> 与 <button> 的 formtarget 属性值,
还可以用作 window.open() 的 windowName 参数值。
src
【属性-作用】被嵌套的页面的 URL 地址。
【值】
- about:blank
可以嵌入一个 遵从同源策略的空白页。(只有 html 基本骨架)
【tip】在 Firefox(version 65 及更高版本)、基于 Chromium 的浏览器、Safari/iOS 中使用代码移除 iframe 的 src 属性会导致 about:blank 被载入 frame。
srcdoc
该属性是一段 HTML 代码,这些代码会被渲染到 iframe 中。如果浏览器不支持 srcdoc 属性,则会渲染 src 属性表示的内容。
其它属性,都不常用。
通信
拓展:跨域的种类
一般有2种形式的跨域:
【前后端进行的跨域请求】浏览器中,不同源的 AJAX 发送的 请求,会造成跨域问题。
【前端页面通讯形成】父子页面之间进行的DOM操作(父子窗口之间的 document 操作)。
(下面主要讲这种)
iframe 通信方式
- 不跨域;
- 主域相同、子域不同;
- 主域不同;
方式1 - 不跨域
【规则】
父页面内 document.getElementById('iframe').contentWindow.document 指向当前 嵌入的子页面 文档。
子页面内 parent.document 获取父页面文档。
【示例】
[父页面l[(https://gitcode.com/fangyinggui/study_code/blob/main/html/iframe-parent.html)
<body>
<h2>父页面</h2>
<textarea id="message">父父父txt</textarea>
<br />
<button id="test">获取内容</button>
<p>下面是 iframe 嵌入的 子页面</p>
<iframe id="iframe" src="/html/iframe-child.html" width="500" height="300"></iframe>
<script>
document.getElementById('test').onclick = function () {
console.log(
1,
document.getElementById('iframe').contentWindow.document.getElementById('message').value // 1 '子子子txt'
)
}
</script>
</body>
[子页面l[(https://gitcode.com/fangyinggui/study_code/blob/main/html/iframe-child.html)
<body>
<h2>子页面</h2>
<textarea id="message">子子子txt</textarea>
<br />
<button id="test">获取内容</button>
<script>
document.getElementById('test').onclick = function () {
console.log(111, parent.document.getElementById('message').value) // 111 '父父父txt'
}
</script>
</body>
方式2 - 主域相同&子域不同
【原理】
同源:当两个页面的协议、端口和域名都相同时,它们被认为是同源的。
跨域限制:不同源的页面之间进行交互会受到浏览器的同源策略限制,例如无法通过 JS 访问对方的 DOM、Cookie 等。
document.domain 可以用来部分地绕过这个限制。
具体来说,如果2个子域名拥有相同的顶级域名,可以通过将它们的 document.domain 设置为相同的顶级域名来实现跨域通信。
【场景】主域相同,子域不同的页面间通讯。
【要求】使用 document.domain 分别在这2个页面 设置为 当前域名下的 同级 或者 父级域名。
- 不能设置为顶级域名;
- 不可以设置为其它形式的域名;
【示例】
1、父页面;
http://fangyinggui.write.com/a.html
<body>
<h2>父页面</h2>
<textarea id="message">父父父txt</textarea>
<br />
<button id="test">获取内容</button>
<p>下面是 iframe 嵌入的 子页面</p>
<iframe id="iframe" src="http://fangqiqi.write.com/b.html" width="500" height="300"></iframe>
<script>
document.domain = 'fangyinggui.online' // (!没有协议、端口)
document.getElementById('test').onclick = function () {
console.log(
1,
document.getElementById('iframe').contentWindow.document.getElementById('message').value // 1 '子子子txt'
)
}
</script>
</body>
2、子页面
http://fangqiqi.write.com/b.html
<body>
<h2>子页面</h2>
<textarea id="message">子子子txt</textarea>
<br />
<button id="test">获取内容</button>
<script>
document.domain = 'fangyinggui.online' // (!没有协议、端口)
document.getElementById('test').onclick = function () {
console.log(111, parent.document.getElementById('message').value) // 111 '父父父txt'
}
</script>
</body>
主域不同
location.hash
【原理】
1、动态改变location.hash,iframe不会重载
2、无论跨域与否,iframe内可以获取自己的 location.hash
3、只要域名相同就能通信,即使 ABC 三层嵌套
【示例】
a.html(http://www.aaa.com/demo/cross/iframe03/a.htm)嵌套了
b.html(http://www.bbb.com/demo/cross/iframe03/b.html)
父页面 a.html 通过 hash 向子页面传值
var iframe = document.getElementById("iframe")
子页面监听 hash 改变,获取 hash 上的值:
//
var hash_url = window.location.hash,
datas = hash_url.split("#")[1].split("&"),
data = {};
for(var i = 0;i<datas.length;i++){
var t = datas[i].split("=");
data[t[0]] = decodeURIComponent(t[1]);
}
document.domain = "jiaju.com";
switch(data["JJtype"])
{
case "height":
try{top.window.document.getElementById(data["iframeID"]).height = data["height"];}catch(e){}
break
case "width":
try{top.window.document.getElementById(data["iframeID"]).width = data["width"];}catch(e){}
break
case "callback":
try{top.window[data["fn"]].call(document,data);}catch(e){}
break
default:
}
【缺点】
1、传递数据量有限;
2、不太安全(明文);
window.name
【是什么?】
name 在浏览器环境中是一个全局window对象的属性
当在 iframe 中加载新页面时,name 的属性值依旧保持不变
name 属性仅对相同域名的 iframe 可访问
【优点】
数据量更大(2M)
更安全
可传递多种数据格式
【劣势】只适用于隐藏iframe的情形
【原理】
A 要把数据传递给 嵌套的页面 B,创建 B,把要传递的数据放入window.name。
打开Chrome的控制台,当前地址为:www.baidu.com。
你在console的控制台中输入window.name=‘moxiao’,然后将当前页面的地址栏的地址改为:mai.qq.com,然后在console的控制台中打印window.name将会显示:‘moxiao’。
调用方法
【目标】跨域 iframe 怎么调用 父页面方法。
同域时
【原理】
父页面内 iframe 加载完成后, $('#iframe')[0].contentWindow 指向 子iframe 的window;
页面:
- window.self:当前窗口自身的引用;
- window.parent:上一级父窗口的引用;
- window.top:最顶层窗口的引用;
【示例】
<body>
<h2>父页面3</h2>
<p>下面是 iframe 嵌入的 子页面</p>
<iframe id="iframe" src="/html/iframe-child3.html" width="500" height="300"></iframe>
<script src="/jquery/dist/jquery.min.js"></script>
<script>
function parentFun() {
console.log('父 页面方法执行')
}
$('#iframe').on('load', function () {
console.log(1, $('#iframe'))
console.log(2, $('#iframe')[0])
console.log(3, $('#iframe')[0].contentWindow)
console.log(4, $('#iframe')[0].contentWindow.childFun)
$('#iframe')[0].contentWindow.childFun()
})
</script>
</body>
<body>
<h2>子页面3</h2>
<script>
function childFun() {
console.log('子 页面方法执行')
}
// 调用当前窗口自身
// window.self.childFun()
// childFun()
// 上一级父窗口调引用
window.parent.parentFun()
// 最顶层窗口的引用
window.top.parentFun() // 这里只嵌套了一层,也指向父窗口
</script>
</body>
【注意 1】必须要在 子 iframe 加载完成,才能在父页面 调用 子iframe 的方法。
【注意 2】当页面中不存在 iframe 嵌套时,则 window.self, window.parent, window.top 三者均是当前窗口自身的引用。
不同域时
【问题】使用上面同源调用方式,会报错。

【解决】使用 HTML5 提供的一个跨域解决方案。(不跨域也能使用)
父页面向子页面通信 iframe.contentWindow.postMessage;
子页面向父页面通信 window.parent.postMessage 或 window.top.postMessage;
接收:直接 window 监听 onmessage 事件即可。
【示例】
1、父页面 (域名A) http://fangying.com/parent.html 定义函数 sayHi。
父页面 (域名B)嵌套子页面 http://fangyingui.online/child.html。
<iframe src="http://fangyingui.online/child.html"></iframe>
<script>
function sayHi() {}
</script>
2、子页面 触发父页面 sayHi 方法;
子页面 发送数据
window.parent.postMessage({ isResetTheme: true },'*');
3、父页面监听 message 事件;
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
console.log(e.data)
})
【注意】postMessage 传值,无法传递 子iframe 的方法(会报错)。
(变通解决,在父页面定义同名的方法,用上面传递过来的参数,变相的解决)
1166

被折叠的 条评论
为什么被折叠?



