換個標簽寫前端模板


前端模板中,我們通常使用 script/textarea 來存放模板代碼,然后使用 innerHTML/value 屬性來獲取模板內容進行解析和拼裝。

<script type="text/x-template" id="tpl">
    <h1><%=data.title%></h1>
    <p><%=data.content%></p>
</script>
<script>
    var htmlTpl = document.getElementById("tpl").innerHTML;
    tplEngine(htmlTpl, {
        title: "This is title",
        content: "This is content"
    });
</script>

關於 tplEngine 這個 Javascript 模板引擎,之前也寫了篇 文章 介紹過,這里就不贅述了。除了使用 script 標簽,textarea 也可以達到同樣的效果,但是本文敘述的重點並不是如何去解析一個 JavaScript 模板。

W3C工作組在 HTML 中加入了一個新的標簽 ——TEMPLATE。他提供了一個可以定義 HTML 代碼片段的機制,下面就來詳細說說這個 TEMPLATE 標簽。

本文地址:http://www.cnblogs.com/hustskyking/p/javascript-template-tag.html,轉載請注明源地址。

一、先看 DEMO

運行下面的 demo,或許你已經知道了一些東西了。

<ul id="list">
    <!-- TEMPLATE 模板 -->
    <template id="tpl">
        <li><span></span> - <span></span></li>
    </template>
</ul>
<button id="btn">見證奇跡的時刻→</button>
<script>
    var datas = [
        {name:"李靖", age:"21"},
        {name:"Barret Lee", age:"21"}
    ];
    btn.onclick = function(){
        for(var i = 0, len = datas.length; i < len; i++){
            var data = datas[i];
            // 獲取模板代碼
            var htmlTpl = tpl.content.cloneNode(true);
            // 插入數據
            var spans = htmlTpl.querySelectorAll("span");
            spans[0].textContent = data.name;
            spans[1].textContent = data.age;
            // 插入到 DOM 中
            list.appendChild(htmlTpl);
        }
    };
</script>

這里使用的 template 標簽,標簽的內容沒有被解析,我們並沒有也使用 innerHTML 這種暴力手段獲取模板內容。

二、template 標簽特性

  1. 這個標簽可以被定義在任何位置:head 中、body中、甚至是一個 frame 中。
  2. 標簽內容不會顯示出來
  3. Template 標簽不被當做 document 的一部分,你可以去試試彈出 document.getElementById("tpl").length, 或者看看他其他的屬性,得到的結果都是 undefined。
  4. 標簽內容在被應用之前,都是 inactive 狀態,也就是說模板中的 img、audio、script 標簽都不會執行(加載)

三、瀏覽器對 template 標簽的解析

每一個 template 元素都會和一個 DocumentFragment 對象關聯,當一個 template 元素被創建時,瀏覽器會運行如下操作:

  1. 讓文檔(doc)是模板元素的ownerDocument的相應的模板內容擁有者文檔(owerDocument)。
  2. 創建一個 DocumentFragment 對象,這個對象的擁有者文檔(owerDocument)為 doc
  3. 將模板文檔的 content 內容放到上述新創建的 DocumentFragment 中

上面的過程我是翻譯 w3c 的規范文檔,讀起來相當晦澀,如果你了解 shadowDOM,那理解起來就輕松了,template 在解析是,其內容被解析成一個 shadowDOM,我們只能使用 content 屬性來獲取到這個 shadowDOM 的內容。

四、兼容性與需要注意的地方

很可惜,這玩意兒雖然好用,但 IE 目前還不支持,當然 Chrome 32+ | Firefox 25+ 都提供了支持。

1. 克隆節點而不是直接使用

從上面的 demo 中,可以發現,獲取 template 標簽的內容,其方式是:

document.getElementById("tpl").content

但是我並不是直接將 content 賦值給 htmlTpl,而是:

htmlTpl = tpl.content.cloneNode(true);

為什么要這么做呢?如果你不是用 cloneNode,而是直接將內容 appendChild 到 DOM 樹中,documentFragment 內的內容就會被清空,上面我們說了 template 標簽內容就是一個 documentFragment 的 shadowDOM,所以應該使用 cloneNode 或者 importNode 方法將內容復制到 DOM 中,這樣才能保證這個 shadowDOM 內容不被清空,從而可以復用(你可以把上面 demo 的 cloneNode 函數去掉,看看結果如何)。

2. 不支持 template 標簽的降級處理

其實也沒有比較好的降級處理方案,如果你在 template 中放了 script 或者 img 節點,這些內容都會被解析出來,你阻止不了,所以如果你的程序要兼容所有的瀏覽器,暫時就不要用了。當然,你可以做這樣的判斷:

if (!"content" in document.createElement("template")){
    // code here..
    return;
}

3. 模板中嵌入模板

在 script 標簽中嵌入一個 script 標簽,這個幾乎是不可能的事情吧,但是 template 可以:

<template id="ulList">
    <li>
        <strong><%=content%></strong>
        <template>
            <div>
                <p><%=detail%></p>
            </div>
        </template>
    </li>
</template>

至於插入之后是個什么效果,讀者可以自己去瀏覽器中查看。這種插入方式是有使用場景的,很多時候我們都是給需要應用模板的元素設置一個 id 或者 class ,方便找到他們,而這種直接插入的方式,我們可以利用模板代碼直接找到需要應用模板的元素,如:

var tpl = ulList.getElementsByTagName("template")[0]; // 獲取模板
var toBox = tpl.parentNode; // 直接定位要插入的位置
toBox.appendChild(tpl.content.cloneNode(true)); // 插入

五、拓展 web components

Web Components 是一些規范,旨在以瀏覽器原生的方式向外提供組件,它的規范如下:

  1. 模板(Templates)可以將不必立即渲染的元素,不必立即執行的腳本放入這里。
  2. 裝飾器(Decorators)
  3. Shadow DOM
  4. 自定義元素(Custom Elements),實現自定義html標簽,及屬性。擁有同原生組件一樣的生命周期
  5. Imports, 指定引入的組件文檔及類型

其實本文提到的內容就是 web components 的冰山一角,感興趣的童鞋可以去讀一讀相關的內容。

六、小結

本文稀里嘩啦說了一大串,主要是簡單介紹 web components 中的 template 標簽,用以替換模板代碼容器 script/textarea,web components 肯定是 web 發展的一個大頭,尤其是移動開發上,很有必要深入研究。

七、參考資料

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM