MOYUN(/Java/SQL/Linux/DevOps/运维/架构/管理/敏捷/开发)

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、背景

  doT.js 灵感来源于搜寻基于 V8 和 Node.js ,强调性能,最快速最简洁的 JavaScript 模板函数。 它在 Node.js 和浏览器两端都彰显出卓越的性能。 在我搜寻期间,两款模板引擎引起了我的注意,激发了创造 doT 的灵感。
  第一个是 jQote2,一个 jQuery 插件,它使用字符串拼接,避免使用 'with' 声明,它是首个追求速度的引擎。 
  第二个是 underscore.js ,其中有一个设计精巧、扩展友好的模板函数。doT.js 快速,小巧且毫无依赖。
  前端渲染有很多框架,而且形式和内容在不断发生变化。这些演变的背后是设计模式的变化,而归根到底是功能划分逻辑的演变:MVC—>MVP—>MVVM(忽略最早混在一起的写法,那不称为模式)。近几年兴起的React、Vue、Angular等框架都属于MVVM模式,能帮我们实现界面渲染、事件绑定、路由分发等复杂功能。但在一些只需完成数据和模板简单渲染的场合,它们就显得笨重而且学习成本较高了。

  例如,在美团外卖的开发实践中,前端经常从后端接口取得长串的数据,这些数据拥有相同的样式模板,前端需要将这些数据在同一个样式模板上做重复渲染操作。

  解决这个问题的模板引擎有很多,doT.js(出自女程序员Laura Doktorova之手)是其中非常优秀的一个。下表将doT.js与其他同类引擎做了对比:

  

  从上可以看出doT.js更值得推荐,它的主要优势在于:

  1. 小巧精简,源代码不超过两百行,6KB的大小,压缩版只有4KB;
  2. 支持表达式丰富,涵盖几乎所有应用场景的表达式语句;
  3. 性能优秀;
  4. 不依赖第三方库。

二、DOT.js的API标签介绍

  1、{{ }} JS原生态代码
  2、{{= }} 变量运算,赋值 {{=it.f1 + it.f2}}
  3、{{! }} 赋值并且编码
  4、{{# }}
  5、{{## #}}
  6、{{? }} 条件语句
  7、{{~ }} 循环
  注:其实条件语句和循环可以用{{if}}{{else if}}{{for(var i=0;i<length;i++)}}来代替,也就是JS的原生态代码

  <script type="text/html" id="tpl">
      <div>
          <a>name:{{= it.name}}</a>
          <p>age:{{= it.age}}</p>
          <p>hello:{{= it.sayHello() }}</p>
          <select>
              {{~ it.arr:item}}
                  <option {{?item.id == it.stringParams2}}selected{{?}} value="{{=item.id}}">
                      {{=item.text}}
                  </option>
              {{~}}
          </select>
      </div>
  </script>
  <script>
      $("#app").html(doT.template($("#tpl").html())({
          name:'stringParams1',
          stringParams1:'stringParams1_value',
          stringParams2:1,
          arr:[{id:0,text:'val1'},{id:1,text:'val2'}],
          sayHello:function () {
              return this[this.name]
          }
      }));
  </script>


  以上代码可以看出doT.js的设计思路:将数据注入到预置的视图模板中渲染,返回HTML代码段,从而得到最终视图。

  

  和后端渲染不同,doT.js的渲染完全交由前端来进行,这样做主要有以下好处:

  1. 脱离后端渲染语言,不需要依赖后端项目的启动,从而降低了开发耦合度、提升开发效率;
  2. View层渲染逻辑全在JavaScript层实现,容易维护和修改;
  3. 数据通过接口得到,无需考虑后端数据模型变化,只需关心数据格式。


  

三、DOT.js使用方法

   1、最常规用法{{=it.attr}}   

<!-- 要显示的区域 -->
<div id="testid"></div>
<script type="text/x-dot-template" id="useType0">
<p>
    <span>姓名:{{=it.name}}</span>
    <span>年龄:{{=it.age}}</span>
    <span>爱好:{{=it.fun}}</span>
</p>
</script>
<!-- 引入js文件 -->
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>

    var testjson={"name":"moyun","age":30,"fun":"逛吃逛吃逛吃逛吃逛吃"},//定义要渲染数据,一般是从后台ajax拉取
        tmpltxt=doT.template(document.getElementById("useType0").innerHTML);//生成模板方法
    document.getElementById("testid").innerHTML=tmpltxt(testjson);//数据渲染
</script>

  运行的结果如下图:

  

 
  2、循环数组{{~}}  

<div id="testid"></div>
<!-- 模板存放区域 修改type类型,以免会被解析成js -->
<script type="text/x-dot-template" id="useType0">
    <ul>
        {{~it:value:index}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span><span>爱好:{{=value.fun}}</span></li>
        {{~}}
    </ul>
</script>
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"fun":"吃东西"},
                {"name":"李四","age":24,"fun":"上网"},
                {"name":"王五","age":70,"fun":"散步,跑步"}
            ],
        tmpltxt=doT.template(document.getElementById("useType0").innerHTML);//生成模板方法
    document.getElementById("testid").innerHTML=tmpltxt(testjson);//数据渲染
</script>

  运行结果如下:
  


  3、条件渲染{{?}}{{??}},相当于原生的if else if  
  运行模式:  

格式:
{{? }} if
{{?? }} else if
{{??}} else

数据源:{“name”:”Jake”,”age”:31}
区域:<div id=”condition”></div>
模板:
<script id=”conditionstmpl” type=”text/x-dot-template”>
{{? !it.name }}
<div>Oh, I love your name, {{=it.name}}!</div>
{{?? !it.age === 0}}
<div>Guess nobody named you yet!</div>
{{??}}
You are {{=it.age}} and still dont have a name?
{{?}}
</script>
调用方式:
var dataEncode = {“uri”:”http://grycheng.com/?keywords=Yoga”,”html”:”<div style=’background: #f00; height: 30px; line-height: 30px;’>html元素</div>”};
var EncodeText = doT.template($(“#encodetmpl”).text());
$(“#encode”).html(EncodeText(dataEncode));
<div id="testid"></div>
<!-- 条件渲染{{?}}{{??}},相当于原生的if else if -->
<script type="text/x-dot-template" id="useType0">
    <ul>
        {{~it:value:index}}
        {{?!value.age}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:年龄数据缺失</span><span>爱好:{{=value.fun}}</span></li>
        {{??!value.fun}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span><span>爱好:无趣的人</span></li>
        {{??}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span><span>爱好:{{=value.fun}}</span></li>
        {{?}}
        {{~}}
    </ul>
</script>
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"fun":"吃东西"},
                {"name":"李四","fun":"上网"},
                {"name":"王五","age":70}
            ],
        tmpltxt=doT.template(document.getElementById("useType0").innerHTML);
    document.getElementById("testid").innerHTML=tmpltxt(testjson);
</script>

  运行结果如下:
    
  
  
  4、编码渲染{{!}},主要是为了防止代码注入以保障安全,如传入一个HTML片段或js片段,它会以字符串的形式渲染  

<div id="testid"></div>
<script type="text/x-dot-template" id="useType0">
    <ul>
        {{~it:value:index}}
        {{?value.bz}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span><span>爱好:{{!value.html}}</span></li>
        {{??}}
        <li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span><span>爱好:{{=value.html}}</span></li>
        {{?}}
        {{~}}
    </ul>
</script>
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"html":"<b>这里是一个html标签</b>","bz":true},
                {"name":"李四","age":24,"html":"<b>另外一个标签</b>","bz":false}
            ],
            tmpltxt=doT.template(document.getElementById("useType0").innerHTML);
    document.getElementById("testid").innerHTML=tmpltxt(testjson);
</script>

  运行结果如下:
  


  5、支持共用模块定义{{##def.}}定义,{{#def.}}引用模块  

<div id="testid"></div>
<script type="text/x-dot-template" id="useType0">
    <!-- 模块定义0 -->
    {{##def.togeter0:
    <li>
        <span>姓名:{{=value.name}}</span>
        <span>年龄:{{=value.age}}</span>
        <span>爱好:{{!value.html}}</span>
    </li>
    #}}
    <!-- 模块定义1 -->
    {{##def.togeter1:
    <li>
        <span>姓名:{{=value.name}}</span>
        <span>年龄:{{=value.age}}</span>
        <span>爱好:{{=value.html}}</span>
    </li>
    #}}
    <ul>
        {{~it:value:index}}
        {{?value.bz}}
        <!-- 引用模块0 -->
        {{#def.togeter0}}
        {{??}}
        <!-- 引用模块1 -->
        {{#def.togeter1}}
        {{?}}
        {{~}}
    </ul>
</script>
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"html":"<b>这里是一个html标签</b>","bz":true},
                {"name":"李四","age":24,"html":"<b>另外一个标签</b>","bz":false}
            ],
        tmpltxt=doT.template(document.getElementById("useType0").innerHTML);
    document.getElementById("testid").innerHTML=tmpltxt(testjson);
</script>

  运行结果如下:
  
  注:模块定义也可以一个json数据定义,再在生成模板函数函数的时候传入即可,示例如下,其中tmpljson就是在外面以json定义的模块:  

<div id="testid"></div>
<script type="text/x-dot-template" id="useType0">
    {{##def.togeter0:
    <li>
        <span>姓名:{{=value.name}}</span>
        <span>年龄:{{=value.age}}</span>
        <span>爱好:{{!value.html}}</span>
    </li>
    #}}
    {{##def.togeter1:
    <li>
        <span>姓名:{{=value.name}}</span>
        <span>年龄:{{=value.age}}</span>
        <span>爱好:{{=value.html}}</span>
    </li>
    #}}
    <ul>
        {{~it:value:index}}
        {{?value.bz===true}}
        {{#def.togeter0}}
        {{??value.bz===false}}
        {{#def.togeter1}}
        {{??}}
        {{#def.testmode}}
        {{?}}
        {{~}}
    </ul>
</script>
<script src="https://cdn.bootcss.com/dot/1.1.0/doT.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"html":"<b>呵呵</b>","bz":true},
                {"name":"李四","age":24,"html":"<b>哈哈</b>","bz":false},
                {"name":"李四","age":24,"html":"<b>哈哈</b>"}
            ],
    tmpljson={"testmode":"<li><span>姓名:{{=value.name}}</span><span>年龄:{{=value.age}}</span></li>"},
    tmpltxt=doT.template(document.getElementById("useType0").innerHTML,undefined,tmpljson);
    document.getElementById("testid").innerHTML=tmpltxt(testjson);
</script>

  

  6、用原生的循环,条件渲染,灵活调用  

<div id="testid"></div>
<script type="text/x-dot-template" id="useType0">
    {{##def.togeter0:
    <li><span>姓名:{{=itz.name}}</span>
        <span>年龄:{{=itz.age}}</span>
        <span>爱好:{{!itz.html}}</span>
    </li>
    #}}
    {{##def.togeter1:
    <li>
        <span>姓名:{{=itz.name}}</span>
        <span>年龄:{{=itz.age}}</span>
        <span>爱好:{{=itz.html}}</span>
    </li>
    #}}
    <ul>
        {{ for(var i=0;i<it.length;i++){ }}
        {{ var itz=it[i]; }}
        {{ if(itz.bz){ }}
        {{#def.togeter0}}
        {{ }else{ }}
        {{#def.togeter1}}
        {{ } }}
        {{ } }}
    </ul>
</script>
<script type="text/javascript" src="doT.min.js"></script>
<script>
    var testjson=[
                {"name":"张三","age":31,"html":"<b>这里是一个html标签</b>","bz":true},
                {"name":"李四","age":24,"html":"<b>另外一个标签</b>","bz":false}
            ],
            tmpltxt=doT.template(document.getElementById("useType0").innerHTML);
    document.getElementById("testid").innerHTML=tmpltxt(testjson);
</script>

   

四、参考

http://jinlong.github.io/doT/
https://github.com/olado/doT
https://qiaolevip.github.io/frontend-template-engines/doT.html

 

posted on 2017-04-28 08:27  moyun-  阅读(1014)  评论(0编辑  收藏  举报