深入理解iframe

本文并不是一篇iframe API文檔講解坎匿,因此想了解iframe API的同學請移步 MDN, 我將在現(xiàn)在瀏覽器的角度與大家取探討iframe, 因此筷登,本文中雖然會提及一些iframe在舊瀏覽器中的應用知市, 但并不會去講解。 所以司恳,您對iframe在舊瀏覽器中的應用場景感興趣的話,還請自己搜索相關資料绍傲。 同時扔傅, 我也會從淺入深的來與大家探討iframe中的一些特性、各種現(xiàn)代瀏覽器中的渲染模式烫饼、應用場景猎塞、以及在現(xiàn)代開發(fā)中的影響。

什么是iframe

在HTML中有三種結(jié)構特征:樹結(jié)構枫弟、層次結(jié)構邢享、框結(jié)構。iframe正是框結(jié)構中的一員淡诗。每個iframe中都是一個獨立的沙箱骇塘,它們擁有自己的window以及DOM。

為什么需要理解它

雖說在日常開發(fā)中韩容,我們應盡量少使用iframe款违,但在一些特殊場景下,我們也是不可避免需要使用iframe群凶。因此插爹,深入理解iframe能夠讓我們更合理的使用它。

渲染與阻塞

前面講到iframe是HTML三種結(jié)構中的框結(jié)構,框結(jié)構中還有另外兩個元素:framesetframe赠尾,但它們都已廢棄力穗,不再推薦使用。
每一個框結(jié)構都有一個獨立的HTML文檔气嫁,而不包含以上三種框結(jié)構中任意一種的網(wǎng)頁就是最簡單的框結(jié)構当窗。其示圖如下:

frame.png

對應的,復雜的框結(jié)構即多個框結(jié)構復合在一個頁面中寸宵, 其示圖如下:


frames.png

像上圖中的多框結(jié)構崖面,非常不適合移動端,因為這種結(jié)構的頁面多觸控操作非常不友好梯影。 到此巫员,對于框結(jié)構的基礎知識普及便告一段落了, 下面筆者將分別從 Chrome甲棍、Firefox简识、Safari、IE 11的測試結(jié)果來分析iframe在不同瀏覽器中的渲染模式以及阻塞情況救军,代碼如下:
我們先定義iframe要引用的頁面财异,并編寫如下代碼:

const start = Date.now();
const limit = function() {
return Date.now() - start;
}
while(limit() <= 1000 * 5) {}

接下來倘零, 在主頁面中引入它:

<iframe src="./frame-sets.html"></iframe>

代碼很簡單唱遭, 就是讓iframe 阻塞至少5秒鐘,接下來分別在 Chrome呈驶、Firefox拷泽、Safari、IE11 中測試阻塞情況:

Chrome Firefox Safari IE11
阻塞主頁面渲染 false true true true
阻塞主頁面onload true true true true

從結(jié)果來看袖瞻,阻塞onload并無異議司致,從來都是如此,但是驚訝的發(fā)現(xiàn)在Chrome中并不會阻塞主頁面的渲染聋迎, 我猜Chrome為iframe創(chuàng)建來一個單獨的沙箱進程吧脂矫。

無阻塞加載iframe

前面講了iframe與阻塞,在不同的瀏覽器中表現(xiàn)大致相同(只有Chrome不會阻塞主頁面渲染霉晕,onload則都會受到阻塞)庭再。在極大多數(shù)情況下,iframe都會阻塞主頁面的渲染牺堰, 所以我們急需采用一種不阻塞主頁面渲染的加載iframe的方式拄轻。那如果才能做到無阻塞加載iframe呢?思路有二:1. 直接使用setTimeout異步加載iframe伟葫;2. 在頁面觸發(fā)onload之后加載iframe恨搓。話不多說, 直接亮代碼:

// setTimeout 形式
setTimeout(function() {
frame.src = 'other-page-url';
}, 0);

這種方式十分簡潔, 但是需要注意的是斧抱, 如果你需要在頁面onload后執(zhí)行某些操作的時候常拓, 需要在 setTimeout 回調(diào)中去綁定load函數(shù)。

window.addEventListener('load', function() {
iframe.src = 'other-page-url';
});

這種方式也是簡單粗暴辉浦,而且沒有setTimeout方式靈活墩邀, 沒辦法準確到iframe加載完后, 在主頁面做一些操作盏浙。

iframe與跨域

跨域是我們開發(fā)過程中經(jīng)常遇到的問題眉睹,而如何解決跨域的問題, 網(wǎng)絡上已經(jīng)有非常多可行的方案废膘, 至于最終選擇何種方案去處理竹海, 還得結(jié)合實際業(yè)務場景選擇最合適的方案。接下來丐黄,我們將縮小解決方案的范圍斋配, 只限定在iframe中去講解幾種跨域方案。
為了模擬跨域灌闺, 我們更改本地hosts艰争。 以mac os 為例:
cd //
cd private/etc
vim hosts
添加如下代碼:

127.0.0.1    demo.com
127.0.0.1    cross.demo.com
127.0.0.1    other.com
  • 方案一:
    document.domain,這是瀏覽器暴露出來的一個準只讀屬性(之所以說它是準只讀屬性桂对,是因為它可以設置為當前域名的超級域)甩卓,利用這個特性,可以實現(xiàn)主域名相同子域名不同的網(wǎng)頁實現(xiàn)通信蕉斜。代碼如下:
    main.html(http://demo.com:15100/main.html)
document.domain = 'demo.com';
window.alertFrameMsg = function(msg) {
alert(msg);
}
const frame = document.querySelector('#myFrame');
frame.src = 'http://cross.demo:15100/frame-sets.html';

frame-sets.html(http://cross.demo:15100/frame-sets.html)

document.domain = 'demo.com';
parent.alertFrameMsg('hello, world!');

如你所見逾柿, 只需要將兩者的document.domain設置為超域, 就可以實現(xiàn)主頁面與iframe的跨域通信了宅此。而且相互之間的訪問非常自由(可以雙向通信)

  • 方案二:
    window.postMessage 机错,HTML5提供的API,可以安全的啟用跨域通信父腕。語法非常簡單:targetWindow.postMessage(data, targetOrigin)弱匪,第一個參數(shù)是要傳遞的數(shù)據(jù),令人高興的是將要發(fā)送到目標window的數(shù)據(jù)璧亮,會采用結(jié)構克隆化算法序列化萧诫, 這意味著我們無需自己序列化,即可安全的傳輸數(shù)據(jù)對象到目標window杜顺。如何在目標窗口接收到數(shù)據(jù)呢财搁?編寫如下代碼即可:
window.addEventListener('message', function(evt) {
console.log(evt.data);
}, false);

evt.data 即是 postMessage 中傳遞過來的數(shù)據(jù)! 結(jié)合上下文躬络, 綜合起來:
main.html

window.frames['myFrame'].contentWindow.postMessage({name: 'injser', age: 18}, 'http://other-demo.com:15100');

frame-sets.html

window.addEventListener('message', function(evt) {
console.log(evt.data);
}, false);

這兩種跨域方式在iframe中驗證都是可用的尖奔, 至于以前一些可用的方案,比如:location.hash、cross-fragment等提茁, 在現(xiàn)代瀏覽器匯總基本驗證已不可行淹禾。 因此并沒有在這里做出講解。
最后茴扁, 作為一名正在路上的前端er, 文章中難免有失誤的地方铃岔。 如有發(fā)現(xiàn), 歡迎勘誤峭火!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毁习,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子卖丸,更是在濱河造成了極大的恐慌纺且,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稍浆,死亡現(xiàn)場離奇詭異载碌,居然都是意外死亡,警方通過查閱死者的電腦和手機衅枫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門嫁艇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弦撩,你說我怎么就攤上這事步咪。” “怎么了孤钦?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵歧斟,是天一觀的道長纯丸。 經(jīng)常有香客問我偏形,道長,這世上最難降的妖魔是什么觉鼻? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任俊扭,我火速辦了婚禮,結(jié)果婚禮上坠陈,老公的妹妹穿的比我還像新娘萨惑。我一直安慰自己,他們只是感情好仇矾,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布庸蔼。 她就那樣靜靜地躺著,像睡著了一般贮匕。 火紅的嫁衣襯著肌膚如雪姐仅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機與錄音掏膏,去河邊找鬼劳翰。 笑死,一個胖子當著我的面吹牛馒疹,可吹牛的內(nèi)容都是我干的佳簸。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼颖变,長吁一口氣:“原來是場噩夢啊……” “哼生均!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腥刹,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤疯特,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肛走,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漓雅,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年朽色,在試婚紗的時候發(fā)現(xiàn)自己被綠了邻吞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡葫男,死狀恐怖抱冷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梢褐,我是刑警寧澤旺遮,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站盈咳,受9級特大地震影響耿眉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鱼响,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一鸣剪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丈积,春花似錦筐骇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唬滑,卻和暖如春告唆,著一層夾襖步出監(jiān)牢的瞬間莫秆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工悔详, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镊屎,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓茄螃,卻偏偏與公主長得像缝驳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子归苍,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容