• knockoutJS学习笔记02:jsRender模板引擎


      上一篇最后提到了模板,并尝试自己编写一个最简单版本;有些朋友可能用过 jqtmpl,这是一个基于jquery的模板引擎,不过它已经不再更新了,而且据说渲染速度比较慢。这里介绍另外一个模板引擎:jsRender。个人觉得这些东西学习起来还是很简单的,挑一个看看就行,实际要用到了哪个,官网看看demo也就会用了。之所以选择jsRender,因为它具有以下特点:

    • 简单直观
    • 功能强大
    • 可扩展的
    • 快如闪电

      当然,谁都会自己给自己的产品下这样定义。不过我用完后,确实发现它:简单直观、功能强大、扩展性强;至于快如闪电...,有兴趣的朋友可以测试看看有多快!接下来就让我们学习jsRender的运用,这里用的是1.0版本。

    一、基础

      jsRender 三个最重要的概念:模板、容器和数据。最重要的是:view(视图) 是我们定义的模板,上下文是视图所用的对象。

      先来看一下模板的基本标签:{{:}} 和 {{>}}(或{{html:}})。两者都可以输出内容,不过后者是经过html编码的。jsRender有几种方式可以渲染数据:

      假设模板如下:

    <script type="text/tmp" id="tmp1">
        <p>my name is: {{:name}}</p>
        <p>i am: {{:info.age}} years old</p>
    </script>
    

       数据如下:  

        var data = {
            name : "tom",
            info : {age : 19}
        }
    

      1.无编译前渲染。直接指定模板。例子:

        var html = $("#tmp1").render(data);
            console.log(html);

      2.编译后渲染。指定模板或字符串。

        2.1 指定模板。效果同1。例子:

          var template = $.templates("#tmp1");
          var html = template.render(data);
          console.log(html);

        2.2 指定模板名称

          2.2.1 传递字符串

            var template = $.templates("tmp1","<b>{{:name}}</b>");
                var html = $.render.tmp1(data);
                console.log(html);

          2.2.2 传递多个模板名称

            var template = $.templates({
                "tmp1":$("#tmp1").html(),
                "tmp2":$("#tmp2").html()
               });
              var html = $.render.tmp1(data);    
              console.log(html);

    二、逻辑判断和循环

      2.1 if-else

      语法:{{if condition}} ... {else condition} ... {{else}}... {{/if}}

      注意这里是 if-else-else,而不是 if-else if-else。例子:  

    <script type="text/tmp" id="tmp4">
        <p>my name is: {{:name}}</p>
        <p>我是:
        {{if info.age >= 18}}
            成年人
        {{else}}
            未成年
        {{/if}}
        </p>
    </script>
    var html = $("#tmp4").render(data);
    $("#list").html(html);
    

      2.2 for

      语法:{{for}} ... {{/for}}

      2.2.1 简单for。例子:  

        <script type="text/tmp" id="tmp5">
            {{for}}
                <li>id:{{:ID}} name:{{:Name}}</li>
            {{/for}}    
        </script>
        var arr = [
            { ID: 1, Name: "tom" },
            { ID: 2, Name: "jack" },
            { ID: 3, Name: "lucy"}
        ];    
        var html = $("#tmp5").render(arr);
        $("#list").html(html);    
    

      2.2.2 嵌套for。

      语法:{{for}}...{{for 当前上下文}} ... {{/for}} ... {{/for}}

      被嵌套的for 可以指定要遍历的属性的名称。#getIndex() 和 #data 会在下面提到。例子:  

    <script type="text/tmp" id="tmp7">    
        {{for}}
            <li>
                name:{{:name}}
                <ul>
                    {{for hobbies}}
                        <li>{{:#getIndex() + 1}}:{{:#data}}</li>
                    {{/for}}
                </ul>
            </li>
        {{/for}}    
    </script>
    arr = [
         { name: "tom", hobbies: ["篮球", "足球"] },
         { name: "jack", hobbies: ["篮球", "橄榄球"] },
         { name: "lucy", hobbies: ["游泳", "羽毛球"] }
    ];
    var html = $("#tmp7").render(arr);
    $("#list").html(html);
    

      2.2.3 分离for。

      语法:{{for 上下文 tmpl="模板id" /}}

      如果for的逻辑比较复杂,嵌套的for就会让我们的模板变得复杂,维护难度加大;我们可以将for分离,以上面的例子,可以将for放到一个新的模板,然后通过 tmpl属性指定。例子:

    <script type="text/tmp" id="tmp8">    
        {{for}}
            <li>
                name:{{:name}}
                <ul>
                    {{for hobbies tmpl="#tmp9" /}}
                </ul>
            </li>
        {{/for}}    
    </script>
    <script type="text/tmp" id="tmp9">    
        <li>{{:#getIndex() + 1}}:{{:#data}}</li>    
    </script>
    var html = $("#tmp8").render(arr);
    $("#list").html(html);
    

    三、#data、#index、#parent

      开始提到,我们定义的模板就是视图,用到的对象就是上下文。

      #data 当前的上下文,有时候它是很有用的,例如我们返回的是最简单的数组[1,2,3,4],这时没法通过{{:属性}} 的形式去获得,通过{{#data}}即可。另外,可以指定上下文,例如上面的 hobbies,内嵌的for的上下文 #data 就是hobbies,而外部的 #data 是整个arr。

      #index 当前下标。应该用 #getIndex() 去获得。

      #parent 当前上下文所在的视图。parent 属性可以一直往上查找视图,视图的data属性就是当前上下文。例如如果我们要在内嵌的for获得外部的name属性,就可以通过 #parent.parent.data.name 获得。

    四、扩展应用

      上面的基本用法已经可以满足大部分需求了。以下几个扩展都是为了分离视图和逻辑的,试想一下,如果我们的视图里还需要大量的逻辑判断或计算,全都写在一起,那会非常麻烦和难以维护。视图最好就是简单的标签,而逻辑都写在js里。jsRender是在视图上进行扩展的。

    4.1 自定义标签 Tag

      我们可以把标签里的逻辑移到自定义标签里。

      语法:1.视图 {{"标签名称" 标签参数 附加参数}}
               2.逻辑 $.views.tags({"标签名称":function(参数){this.tagCtx.props.prefix附加参数}}) 

      例子:

        <script type="text/tmp" id="tmp10">
            {{for}}
                <li>
                    name:{{:name}}                            
                    hobbies: {{format hobbies prefix="@" /}}
                </li>
            {{/for}}         
        </script>
        $.views.tags({
            "format":function(hobbies){
                if(!hobbies || hobbies.length <= 0){
                    return "无";
                }
                var result = "";
                for(var i = 0,length = hobbies.length;i < length; i++){
                    result += "," + this.tagCtx.props.prefix + hobbies[i];
                }
                result = result.substring(1);
                return result;
            }
        })
        var html = $("#tmp10").render(arr);
        $("#list").html(html);
    

    4.2 转换器 converter

      转换器可以对输出结果进行处理,例如大小写转换等。

      语法:1. 视图 {{"转化器名称":参数}}
              2. js $.views.converters({"转换器名称":function(参数){...}})

        <script type="text/tmp" id="tmp11">    
            {{for}}
                <li>
                    Upper Name: {{toUpper:#parent.data.name}}
                </li>
            {{/for}}   
        </script>
        $.views.converters({
            "toUpper":function(name){
                if(name){
                    return name.toUpperCase();
                }
            }
        })
        var html = $("#tmp11").render(arr);
        $("#list").html(html)
    

    4.3 辅助函数 Helper

      扩展函数可以对结果进行处理,逻辑判断等等。

      语法 1. 视图 {{~辅助函数名称(参数)}}
              2. js $.views.helpers({"辅助函数名称":function(参数){}})

        <script type="text/tmp" id="tmp12">    
            {{for}}
                <li>
                    name: {{:name}}
                    hobbies: {{:~concat(hobbies)}}
                </li>
            {{/for}}   
        </script>
        $.views.helpers({
            "concat":function(hobbies){            
                if(!hobbies || hobbies.length <= 0){
                    return "";
                }
                var result = "";
                for(var i = 0,length = hobbies.length;i < length;i++){
                    result += "&&" + hobbies[i];
                }
                return result.substring(2);
            }
        })
        var html = $("#tmp12").render(arr);
        $("#list").html(html);
    

    五、总结

      jsRender还是比较新的,使用起来也比较方便。不过我们看到我们的数据和页面之间是一个单向的过程,而且是一次性的单向;也就是当我们的数据改变时,视图不能自动更新,而界面的数据改变时,实际数据也不能自动改变。设想一下,如果数据和视图是双向的,其中一个改变,都可以自动更新另外一个,那不就最好了,我们只需要操作数据,不需要操作dom了。这就是mvvm的机制,前端的mvvm框架有很多:knockout、angular等。下一篇将开始介绍knockout。

  • 相关阅读:
    使用JavaScriptSerializer进行JSON序列化
    清除浮动
    后台请求url数据
    设置Response中的ContentType
    javascript阻止事件冒泡
    如何启动Nunit的调试功能
    AjaxControlToolKit(整理)二···(全部源代码)
    DataRow对象数据绑定问题
    修改程序之感悟
    关于虚函数一个很好的解释
  • 原文地址:https://www.cnblogs.com/4littleProgrammer/p/4808221.html
Copyright © 2020-2023  润新知