Template、Shadow DOM及Custom Elements 讓你建立UI元件比以前更容易了。但是像HTML、CSS、JavaScript這樣的資源仍然需要一個個地去載入,這是很沒效率的。
刪除重複依賴也並不簡單。例如,現在載入jQuery UI或Bootstrap就需要為JavaScript、CSS及Web Fonts新增單獨的標籤。如果你的Web 元件應用了多重的依賴,那事情就變得更為複雜。
HTML 匯入讓你以一個合併的HTML檔案來載入這些資源。
使用HTML匯入
為載入一個HTML檔案,你需要增加一個link標籤,其rel屬性為import,herf屬性是HTML檔案的路徑。例如,如果你想把component.html載入到index.html:
index.html
1 |
<link rel="import" href="component.html" > |
你可以往HTML匯入檔案(譯者注:本文將“ the imported HTML”譯為“HTML匯入檔案”,將“the original HTML”譯為“HTML主檔案”。例如,index.html是HTML主檔案,component.html是HTML匯入檔案。)新增任何的資源,包括指令碼、樣式表及字型,就跟往普通的HTML新增資源一樣。
component.html
1 2 |
<link rel="stylesheet" href="css/style.css"> <script src="js/script.js"></script> |
doctype、html、 head、 body這些標籤是不需要的。HTML 匯入會立即載入要匯入的文件,解析文件中的資源,如果有指令碼的話也會立即執行它們。
執行順序
瀏覽器解析HTML文件的方式是線性的,這就是說HTML頂部的script會比底部先執行。並且,瀏覽器通常會等到JavaScript程式碼執行完畢後,才會接著解析後面的程式碼。
為了不讓script 妨礙HTML的渲染,你可以在標籤中新增async或defer屬性(或者你也可以將script 標籤放到頁面的底部)。defer 屬性會延遲指令碼的執行,直到全部頁面解析完畢。async 屬性讓瀏覽器非同步地執行指令碼,從而不會妨礙HTML的渲染。那麼,HTML 匯入是怎樣工作的呢?
HTML匯入檔案中的指令碼就跟含有defer屬性一樣。例如在下面的示例中,index.html會先執行script1.js和script2.js ,然後再執行script3.js。
index.html
1 2 3 |
<link rel="import" href="component.html"> // 1. <title>Import Example</title> <script src="script3.js"></script> // 4. |
component.html
1 2 |
<script src="js/script1.js"></script> // 2. <script src="js/script2.js"></script> // 3. |
1.在index.html 中載入component.html並等待執行
2.執行component.html中的script1.js
3.執行完script1.js後執行component.html中的script2.js
4.執行完 script2.js繼而執行index.html中的script3.js
注意,如果給link[rel=”import”]新增async屬性,HTML匯入會把它當做含有async屬性的指令碼來對待。它不會等待HTML匯入檔案的執行和載入,這意味著HTML 匯入不會妨礙HTML主檔案的渲染。這也給提升網站效能帶來了可能,除非有其他的指令碼依賴於HTML匯入檔案的執行。
跨域匯入
從根本上說,HTML匯入是不能從其他的域名匯入資源的。
比如,你不能從http://webcomponents.org/向 http://example.com/ 匯入HTML 檔案。為了繞過這個限制,可以使用CORS(跨域資源共享)。想了解CORS,請看這篇文章。
HTML匯入檔案中的window和document物件
前面我提過在匯入HTML檔案的時候裡面的指令碼是會被執行的,但這並不意味著HTML匯入檔案中的標籤也會被瀏覽器渲染。你需要寫一些JavaScript程式碼來幫忙。
當在HTML匯入檔案中使用JavaScript時,有一點要提防的是,HTML匯入檔案中的document物件實際上指的是HTML主檔案中的document物件。以前面的程式碼為例,index.html和 component.html 的document都是指index.html的document物件。怎麼才能使用HTML匯入檔案中的document 呢?藉助link中的import 屬性。
index.html
1 2 3 4 5 |
var link = document.querySelector('link[rel="import"]'); link.addEventListener('load', function(e) { var importedDoc = link.import; // importedDoc points to the document under component.html }); |
為了獲取component.html中的document 物件,要使用document.currentScript.ownerDocument.
component.html
1 2 |
var mainDoc = document.currentScript.ownerDocument; // mainDoc points to the document under component.html |
如果你在用webcomponents.js,那麼就用document._currentScript來代替document.currentScript。下劃線用於填充currentScript屬性,因為並不是所有的瀏覽器都支援這個屬性。
component.html
1 2 |
var mainDoc = document._currentScript.ownerDocument; // mainDoc points to the document under component.html |
通過在指令碼開頭新增下面的程式碼,你就可以輕鬆地訪問component.html中的document物件,而不用管瀏覽器是不是支援HTML匯入。
1 |
document._currentScript = document._currentScript || document.currentScript; |
效能方面的考慮
使用HTML 匯入的一個好處是能夠將資源組織起來,但是也意味著在載入這些資源的時候,由於使用了一些額外的HTML檔案而讓頭部變得過大。有幾點是需要考慮的:
解析依賴
假如HTML主檔案要依賴多個匯入檔案,而且匯入檔案中含有相同的庫,這時會怎樣呢?例如,你要從匯入檔案中載入jQuery,如果每個匯入檔案都含有載入jQuery的script標籤,那麼jQuery就會被載入兩次,並且也會被執行兩次。
index.html
1 2 |
<link rel="import" href="component1.html"> <link rel="import" href="component2.html"> |
component1.html
1 |
<script src="js/jquery.js"></script> |
component2.html
1 |
<script src="js/jquery.js"></script> |
HTML匯入自動幫你解決了這個問題。
與載入兩次script標籤的做法不同,HTML 匯入對已經載入過的HTML檔案不再進行載入和執行。以前面的程式碼為例,通過將載入jQuery的script標籤打包成一個HTML匯入檔案,這樣jQuery就只被載入和執行一次了。
但這還有一個問題:我們增加了一個要載入的檔案。怎麼處理數目膨脹的檔案呢?幸運的是,我們有一個叫vulcanize的工具來解決這個問題。
合併網路請求
Vulcanize 能將多個HTML檔案合併成一個檔案,從而減少了網路連線數。你可以藉助npm安裝它,並且用命令列來使用它。你可能也在用 grunt和gulp 託管一些任務,這樣的話你可以把vulcanize作為構建過程的一部分。
為了解析依賴以及合併index.html中的匯入檔案,使用如下命令:
1 |
$ vulcanize -o vulcanized.html index.html |
通過執行這個命令,index.html中的依賴會被解析,並且會產生一個合併的HTML檔案,稱作 vulcanized.html。學習更多有關vulcanize的知識,請看這兒。
注意:http2的伺服器推送功能被考慮用於以後消除檔案的連結與合併。
把Template、Shadow DOM、自定義元素跟HTML匯入結合起來
讓我們對這個文章系列的程式碼使用HTML匯入。你之前可能沒有看過這些文章,我先解釋一下:Template可以讓你用宣告的方式定義你的自定義元素的內容。Shadow DOM可以讓一個元素的style、ID、class只作用到其本身。自定義元素可以讓你自定義HTML標籤。通過把這些跟HTML匯入結合起來,你自定義的web 元件會變得模組化,具有複用性。任何人新增一個Link標籤就可以使用它。
x-component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<template id="template"> <style> ... </style> <div id="container"> <img src="http://webcomponents.org/img/logo.svg"> <content select="h1"></content> </div> </template> <script> // This element will be registered to index.html // Because `document` here means the one in index.html var XComponent = document.registerElement('x-component', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { value: function() { var root = this.createShadowRoot(); var template = document.querySelector('#template'); var clone = document.importNode(template.content, true); root.appendChild(clone); } } }) }); </script> |
index.html
1 2 3 4 5 6 7 8 |
... <link rel="import" href="x-component.html"> </head> <body> <x-component> <h1>This is Custom Element</h1> </x-component> ... |
注意,因為x-component.html 中的document 物件跟index.html的一樣,你沒必要再寫一些棘手的程式碼,它會自動為你註冊。
支援的瀏覽器
Chrome 和 Opera提供對HTML匯入的支援,Firefox要在2014年12月後才支援(Mozilla表示Firefox不計劃在近期提供對HTML匯入的支援,聲稱需要首先了解ES6的模組是怎樣實現的)。
你可以去chromestatus.com或caniuse.com查詢瀏覽器是否支援HTML匯入。想要在其他瀏覽器上使用HTML匯入,可以用webcomponents.js(原名platform.js)。
相關資源
HTML匯入就介紹這麼多了。如果你想學更多關於HTML匯入的知識,請前往: