在 HTML 中包含資源的新思路

做者:scott jehl

翻譯:瘋狂的技術宅html

原文:https://www.filamentgroup.com...前端

未經許可嚴禁轉載程序員

注意:這篇文章描述了一種咱們仍須要測其試性能影響的實驗技術。 它可能最終會成爲一種有用的工具,也有可能成爲不被推薦的作法。 不管哪一種方式,它對咱們來講頗有吸引力!web

只要我一直工做在 Web 上,就須要一種簡單的 HTML 驅動方式,將另外一個文件的內容直接包含在頁面中。 例如,我常常但願向頁面添加額外的 HTML,或者嵌入 SVG 文件的內容,以便咱們能夠爲其設置動畫和樣式。 一般咱們經過使用 JavaScript 獲取文件並將其內容附加到特定元素,或者經過在服務器端去包含文件來實現這種嵌入,但在大多數狀況下,這些方法都不是咱們想要的。面試

本週我在思考如何用一些新的與 fetch 相關的標記模式來實現這一點,例如 rel="preload" 或 HTML import,但我老是得出的相同結論,即這些都不能使你方便地訪問所取得的文件的內容。 而後我想,假設瀏覽器容許我在父文檔中檢索 iframe 的內容,也許一箇舊的 iframe 多是一個很不錯的模式。 事實證實,它確定會的!ajax

一個短小的演示:包含 SVG

下面是一個內聯(嵌入式)SVG 圖形。它是從外部文件 signal.svg中加載的。segmentfault

要加載並嵌入 SVG 文件,我用了下面的標記:瀏覽器

<iframe src="signal.svg" onload="this.before((this.contentDocument.body || this.contentDocument).children[0]);this.remove()"></iframe>

儘管此標記以 iframe 開頭,但若是你使用開發人員工具檢查上面的圖形,將會看到 SVG 的圖標標記,就內嵌在 HTML DOM 中,並且找不到 iframe 元素。 這是由於代碼用 iframe 加載文件,而且在刪除 iframe以前,用 onload 事件在 HTML 中 iframe 的位置以前注入了 iframe 裏的內容。緩存

該方法也適用於 object 元素,不管如何它一般用於引用SVG,因此我認爲這特別好。 對於一個objectsrc 屬性必須用 data 替代:安全

<object data="signal.svg" onload="this.before((this.contentDocument.body || this.contentDocument).children[0]);this.remove()"></object>

另外一個演示:包含 HTML 文件

也許更有用......這是一個使用HTML而不是SVG的例子!

能夠用下面的標記加載:

<iframe src="/images/includespost/htmlexample.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>

一個說明這一個:你可能已經注意到,標記片斷檢查 contentDocument.body 或僅檢查 contentDocument。這是對 HTML 和 SVG 包含進行的規範化檢查。 這是必要的,由於即便 HTML 文件自己只包含一個段落元素,瀏覽器也會建立一個完整的 HTML 文檔來包裝該段落,幷包含 HTML 元素、head、body等。因此該片斷會試圖獲取 iframebody 元素(若是存在),若是不存在,它將會用於整個文檔。

值得注意的是,若是你要導入包含多個元素的 HTML 文件,我建議將其所有包裝在 div 中,以使 iframe 標記可以簡單地查找 body中的第一個子節點。

好處

與咱們過去使用的其餘模式相比,這種模式有一些很明顯的好處:

  • 這是聲明性的。 與大多數自定義 JavaScript 方法不一樣,這個方法是 HTML 驅動的,它在標記中的目的很是清楚,一目瞭然。
  • 它適用於 HTML 或 SVG。 我不肯定你想要包含什麼東西,但這至少知足了我本身的需求。
  • 這是異步的! 內容加載不會阻止頁面渲染,這是 iframe 的性質。
  • 它是緩存友好的。 與服務器端嵌入不一樣,此模式容許咱們包含外部文件,同時容許天然緩存文件以供往後重用。 (使用服務器端包含的內容,在客戶端緩存是可能的,但難以作到)。
  • 不管 JavaScript 是否運行,它都會顯示內容,由於這就是 iframe 的設計目標。 JavaScript 能夠將 iframe 的內容移動到父文檔中,即使失敗了,你仍會看到包含的內容。
  • 它沒有留下任何痕跡:iframe 將內容導入頁面後會被刪除。 注意:你可能但願爲 iframe 指定 border:0; 甚至能夠在加載時安全地隱藏它(或許經過 onerror 事件再次顯示它?)。
  • 它適用於各類瀏覽器:到目前爲止,在個人簡短測試中,它適用於 Chrome,Firefox,Safari 和 Edge。 IE 會顯示 iframe 中的備選內容,但我認爲能夠經過調整 onload 處理中的 JS 來得到對 IE 的支持,由於它目前用的是 IE 不喜歡的語法。 稍微調整一下,我認爲 IE 支持是可能的。
  • 若是你願意的話,它甚至能夠包含在一個 Web 組件中,正如 Andy Bell 巧妙地演示的那樣(這是一個更清晰的標記,但就 JS 依賴性來講更脆弱一點)。

考慮其餘可能的用途頗有趣......也許你能夠引入 HTML 模塊及其相關的 CSS 連接。 或者在文檔或博客文章中嵌入推文或代碼。 它甚至可能用於異步加載和應用常規的 rel=stylesheet 連接,而且優先級較低,不然很難作到(注意:我沒有對這個想法進行太多的測試)。

能夠惰性加載嗎?是的,很快!

使用 iframe 進行此模式的另外一個好處是, iframe 會在進入視口時得到延遲加載的能力。 這能夠用 load ="lazy" 屬性來實現,該屬性也適用於 img 元素。 代碼看起來是這樣:

<iframe src="signal.svg" loading="lazy" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>

可能存在的問題

iframe 在 web 上很經常使用,可是在頁面中過分使用 iframe 可能會致使性能或內存消耗問題。 例如對頁面上全部圖標使用可能會太重,可是對於須要進行動畫和樣式化的特定圖標來講,它可能會很好用。 不過如今我只能作更多的測試。

還有可能存在XSS問題,但我不肯定這與其餘須要注意外部內容的狀況有什麼不一樣。 你仍須要作一般的安全檢查,而且最好將其看做是同域技術,儘管我也不肯定。

就目前而言,這種作法有但願成爲以前將另外一個文件直接包含在頁面中方法的改進。

反饋

咱們將會繼續測試這種模式,若是咱們發現了什麼有趣的內容,會很快發佈後續內容。 若是你有什麼反饋或想法,請隨時在Twitter(https://twitter.com/filamentg...)上與咱們聯繫。 謝謝閱讀!


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索