1. 程式人生 > 實用技巧 >在 HTML 中包含資源的新思路

在 HTML 中包含資源的新思路

注意:這篇文章描述了一種我們仍需要測其試效能影響的實驗技術。 它可能最終會成為一種有用的工具,也有可能成為不被推薦的做法。 無論哪種方式,它對我們來說很有吸引力!

只要我一直工作在 Web 上,就需要一種簡單的html驅動方式,將另一個檔案的內容直接包含在頁面中。 例如,我經常希望向頁面新增額外的html,或者嵌入 SVG 檔案的內容,以便我們可以為其設定動畫和樣式。 通常我們通過使用JavaScript獲取檔案並將其內容附加到特定元素,或者通過在伺服器端去包含檔案來實現這種嵌入,但在大多數情況下,這些方法都不是我們想要的。

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

一個短小的演示:包含 SVG

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

要載入並嵌入 SVG 檔案,我用了下面的標記:

<iframesrc="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,所以我認為這特別好。 對於一個object,src屬性必須用data替代:

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

另一個演示:包含 HTML 檔案

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

可以用下面的標記載入:

<iframesrc="/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等。所以該片段會試圖獲取iframe的body元素(如果存在),如果不存在,它將會用於整個文件。

值得注意的是,如果你要匯入包含多個元素的 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連結,並且優先順序較低,否則很難做到(注意:我沒有對這個想法進行太多的測試)。

廣州設計公司https://www.houdianzi.com 我的007辦公資源網站https://www.wode007.com

可以惰性載入嗎?是的,很快!

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

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

可能存在的問題

iframe在 web 上很常用,但是在頁面中過度使用 iframe 可能會導致效能或記憶體消耗問題。 例如對頁面上所有圖示使用可能會過重,但是對於需要進行動畫和樣式化的特定圖示來說,它可能會很好用。 不過現在我只能做更多的測試。

還有可能存在XSS問題,但我不確定這與其他需要注意外部內容的情況有什麼不同。 你仍需要做通常的安全檢查,並且最好將其看作是同域技術,儘管我也不確定。

就目前而言,這種做法有希望成為之前將另一個檔案直接包含在頁面中方法的改進。