1. 程式人生 > >模板引擎原理及underscore.js使用

模板引擎原理及underscore.js使用

chang ast i++ 外賣o2o 發出 url 市場 star $1

為什麽要使用模板引擎

DOM結構簡單,完全可以使用DOM方法創建DOM樹。$("<td></td").appendTo();

當頁面比較復雜的時候,下面的程序中紅色部分來自JSON中的數據:

<div class="feeds-item hasImg" id="item-702635">

<p class="feeds-item-pic">

<a href="http://gupowang.baijia.baidu.com/article/702635" target="_blank" >

<img src="http://d.hiphotos.baidu.com/news/crop%3D0%2C1%2C612%2C367%3Bw%3D638/sign=243504ed134c510fba8bb85a5d69091c/e1fe9925bc315c6097d9b1ca84b1cb1349547743.jpg

"></a>

</p>

<h3>

<a href="http://gupowang.baijia.baidu.com/article/702635" target="_blank" mon="col=13&amp;pn=2">Snap這款眼鏡真能帶來一場社交革命嗎?</a>

</h3>

<p class="feeds-item-text1">

Snapchat母公司Snap在11月10日推出的一款智能眼鏡——Spectacles,目前在美國亞馬遜網站裏的合作商戶頁面標價依然高達1599

美元,...

</p>

<div class="feeds-item-info">

<p class="labels">

<span class="label">

<a class="labelnm" href="http://baijia.baidu.com/?tn=listarticle&amp;labelid=142650" target="_blank">snap</a>

</span>

<span class="label">

<a class="labelnm" href="http://baijia.baidu.com/?tn=listarticle&amp;labelid=24262" target="_blank">眼鏡</a>

</span>

<span class="label">

<a class="labelnm" href="http://baijia.baidu.com/?tn=listarticle&amp;labelid=26751" target="_blank">社交革命</a>

</span>

</p>

<a href="http://gupowang.baijia.baidu.com/" class="feeds-item-author" target="_blank">姑婆那些事兒</a> <i class="public-v"></i>

<span class="tm">10:14</span>

<span class="count">閱讀(9)</span>

<a href="javascript:;" class="share-article"> <i class="i ishare"></i>

分享

<dl class="changeshare">

<dd class="sina"></dd>

<dd class="qzone"></dd>

<dd class="wechat"></dd>

</dl>

</a>

</div>

</div>

如果使用DOM方法創建上面的結構,太復雜了!不容易進行更改。此時最好的辦法就是“模板引擎”。

模板引擎的原理

就是字符串的replace函數。

最簡單的replace函數:

<script type="text/javascript">
    var str = "我愛楊洋,楊洋很帥,楊洋很會唱歌";
    str = str.replace(/楊洋/g,"李易峰");
    alert(str);
</script>

技術分享圖片

replace函數的第二個參數可以是函數:

    <script type="text/javascript">
        var str = "我愛楊洋,楊洋很帥,楊洋很會唱歌";
        str = str.replace(/楊洋/g,function(){
            return "李易峰";
        });
        alert(str);
    </script>

技術分享圖片

分組捕獲,可以使用$1來參與生成替換字符串,比如把人民幣換成美元。

    <script type="text/javascript">
        var str = "我一共有100元,早飯10元,午飯20元,晚飯15元。";
        str = str.replace(/([\d]+)元/g,function(match,$1){
            return $1 / 6.2 + "美元";
        });
        alert(str);
    </script>

技術分享圖片

模板原理:

    <script type="text/javascript">
        //模板字符串
        var str = "好{{xinqing}}啊,今天我買了{{dongxi}},花了{{qian}}元";
        //字典(數據)
        var dictionary = {
            "xinqing" : "高興",
            "dongxi" : "手機",
            "qian" : 1000
        }
        //數據綁定
        str = str.replace(/{{(\w+)}}/g,function(match,$1){
            return dictionary[$1];
        });
        //顯示結果
        alert(str);
    </script>

模板一共要三步走:

① 準備模板字符串。所謂的模板字符串就是含有模板標記的字符串,模板標記可以任意設置。

② 準備字典(這個名字是前幾年流行的,現在就單純的叫做“數據”)

③ 數據綁定,其實很簡單就是用字典的v去對用替換模板標記k的那個地方。

一般不使用自己開發的模板引擎解析程序,因為不好用,比如模板標記加上空格,就不能識別了。

一般使用underscore來進行模板操作。

    <script type="text/javascript" src="js/underscore-min.js"></script>
    <script type="text/javascript">
        //模板字符串
        var str = "好<%=xinqing%>啊,今天我買了<%=dongxi%>,花了<%=qian%>元";

        //準備編譯函數,使用underscore提供的template函數,接受一個模板字符串,返回一個函數。
        var compiled = _.template(str);
        //數據綁定
        var str2 = compiled({
            "xinqing" : "高興",
            "dongxi" : "手機",
            "qian" : 1000
        });

        alert(str2);
    </script>

技術分享圖片

使用underscore進行模板操作的時候:

① 準備模板字符串,模板標記不能任意執行,必須是<%=%>。其實underscore源碼中可以自由更改。

② 生成一個編譯函數,使用內置的_.template()函數,template就是模板的意思。這個函數接受一個字符串(就是剛才的模板字符串)當做參數,返回一個函數。

③ 數據綁定,直接調用剛才生成的compiled函數,把字典往裏面扔,此時就能返回綁定之後的字符串。

模板引擎的使用

首先我們準備一個復雜JSON:

技術分享圖片

後臺哥哥生成了JSON,他的工作就完成了,不管前端是如何進行數據可視化的。

然後進行界面的HTML、CSS開發,把重復的部分,放到

<script type="text/template"></script>

不一定一定是text/template,只要不是test/javascript就行了。瀏覽器認為遇見了一個陌生的語言,從而靜默,不予處理,不報錯。

把需要使用模板的地方,使用模板標記替換。註意,模板標記中的英語單詞,必須要根據字典中的key來決定。

<script type="text/template" id="feeds_template">
    <div class="feeds">
        <div class="pic">
            <a href="<%= m_display_url %>">
                <img src="<%= m_image_url %>"  />
            </a>
        </div>
        <div class="feed_main">
            <h3>
                <a href="<%= m_display_url %>">
                    <%= m_title %>
                </a>
            </h3>
            <p class="summary">
                <%= m_summary %>
            </p>
            <div class="info">
                <span class="writer"><%= m_writer_name %></span>
                <span><img src="images/v.png"  /></span>
                <span class="time"><%= m_create_time %></span>
                <span class="yuedu">閱讀<b>(<%= hotcount %>)</b></span>
            </div>
        </div>
    </div>
</script>

此時就可以書寫程序:

<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="js/underscore-min.js"></script>
<script type="text/javascript">
    //得到模板字符串
    var template_str = $("#feeds_template").html();
    //生成編譯函數
    var compiled = _.template(template_str);
    //發出Ajax請求,請求字典
    $.get("json/baijia0.txt",function(data){
        //轉為obj對象
        dataobj = typeof data == "object" ? data : eval("(" + data + ")");
        //遍歷數組,得到20本字典。分別數據綁定,分別上樹
        _.each(dataobj.data.list , function(dictionary){
            //數據綁定
            var str = compiled(dictionary);
            //上樹
            $(str).appendTo(".main_news")
        });
    });
</script>

模板修正

模板中存放的是 m_writer_account_type: "0" 或者"2"

此時我們要變為v圖標是否顯示,就可以寫程序:

//發出Ajax請求,請求字典
$.get("json/baijia0.txt",function(data){
    //轉為obj對象
    dataobj = typeof data == "object" ? data : eval("(" + data + ")");
    //遍歷數組,得到20本字典。分別數據綁定,分別上樹
    _.each(dataobj.data.list , function(dictionary){
        //數據綁定
        var str = compiled(dictionary);
        //把字符串變為DOM
        var $dom = $(str);
        //上樹
        $dom.appendTo(".main_news")
        //選擇顯示和隱藏這個v
        if(dictionary.m_writer_account_type == "0"){
            $dom.find(".v").show();
        }else{
            $dom.find(".v").hide();
        }
    });
});

有些時候我們甚至可以補充key:

_.each(dataobj.data.list , function(dictionary){
    //模板修正
    dictionary.biaoqian = "麽麽噠";
    //數據綁定
    var str = compiled(dictionary);
    //把字符串變為DOM
    var $dom = $(str);
    //上樹
    $dom.appendTo(".main_news")
    //選擇顯示和隱藏這個v
    if(dictionary.m_writer_account_type == "0"){
        $dom.find(".v").show();
    }else{
        $dom.find(".v").hide();
    }
});

子模板

來看百度百家的實際應用,此時JSON裏面又有一個數組,需要遍歷:

技術分享圖片

需要生成:

<div class="feeds __web-inspector-hide-shortcut__">
    <div class="pic">
        <a href="http://liukuang.baijia.baidu.com/article/702650">
                <img src="http://h.hiphotos.baidu.com/news/crop%3D0%2C1%2C590%2C354%3Bw%3D638/sign=bd98abbaad0f4bfb989fc4143e7f54c1/b3fb43166d224f4a1f3eb73600f790529822d174.jpg" alt="">
            </a>
    </div>
    <div class="feed_main">
        <h3>
                <a href="http://liukuang.baijia.baidu.com/article/702650">
                    從混戰到三足鼎立,外賣O2O下一個誰先出局?
                </a>
            </h3>
        <p class="summary">
            外賣O2O市場份額顯示出:三強稱霸整個市場的局面越來越明顯。那麽,從上半場的混戰走向如今的三足鼎立,到了外賣O2O三國戰的下半場,又將是怎樣的格局?
        </p>
        <div class="info">
            <span class="writer">劉曠</span>
            <span><img class="v" src="images/v.png" alt=""></span>
            <span class="time">10:25</span>
            <span class="yuedu">閱讀<b>(642)</b></span>
            <span class="labels">
<a href="http://baijia.baidu.com/?tn=listarticle&amp;labelid=19240">外賣O2O</a>
<a href="http://baijia.baidu.com/?tn=listarticle&amp;labelid=10595">市場</a>
            </span>
        </div>
    </div>
</div>

此時方法1,就是DOM法:

// 發出Ajax請求,請求字典
$.get("/json/baijia0.txt",function(data){
    var dataobj = typeof data == "object" ? data : eval("(" + data + ")");
    var list = dataobj.data.list;
    //each函數會遍歷list數組,會讓list中的每一項註入到函數中成為實參
    _.each(list,function(dictionary){
        //數據綁定
        var feedStr = feed_compiled(dictionary);
        //轉為DOM元素
        var $dom = $(feedStr);
        //上樹
        $dom.appendTo(".main_news");
        //決定v是否顯示
        if(dictionary.m_writer_account_type != "0"){
            $dom.find(".v").hide();
        }
        //上標簽
        for(var i = 0 ; i < dictionary.m_label_names.length ; i++){
            $("<a href=‘http://baijia.baidu.com/?tn=listarticle&labelid=" + dictionary.m_label_names[i].m_id + "‘>" + dictionary.m_label_names[i].m_name + "</a>").appendTo($dom.find("span.labels"));
        }
    });
});

方法2子模板,我們有了模板之後,就再也不要去拼接字符串了!

<script type="text/template" id="labels_template">
        <a href="http://baijia.baidu.com/?tn=listarticle&labelid=<%=m_id%>"><%= m_name %></a>
</script>
<script type="text/javascript">
    // 得到模板字符串
    var feed_template_str = $("#feed_template").html();
    var labels_template_str = $("#labels_template").html();
    // 模板編譯函數
    var feed_compiled = _.template(feed_template_str);
    var labels_compiled = _.template(labels_template_str);

    // 發出Ajax請求,請求字典
    $.get("/json/baijia0.txt",function(data){
        var dataobj = typeof data == "object" ? data : eval("(" + data + ")");
        var list = dataobj.data.list;
        //each函數會遍歷list數組,會讓list中的每一項註入到函數中成為實參
        _.each(list,function(dictionary){
            //feed模板數據綁定
            var feedStr = feed_compiled(dictionary);
            //轉為DOM元素
            var $dom = $(feedStr);
            //上樹
            $dom.appendTo(".main_news");
            //決定v是否顯示
            if(dictionary.m_writer_account_type != "0"){
                $dom.find(".v").hide();
            }
            //設置labels
            for(var i = 0 ; i < dictionary.m_label_names.length ; i++){
                var aStr = labels_compiled(dictionary.m_label_names[i]);
                $dom.find("span.labels").append($(aStr));
            }
        });
    });
</script>

模板引擎原理及underscore.js使用