如何使用underscore.js作为模板引擎?


262

我正在尝试学习javascript作为服务器端语言和功能性语言的新用法。几天前,我听说了node.js和express框架。然后我看到了underscore.js作为一组实用程序功能。我在stackoverflow上看到了这个问题 。它说我们可以使用underscore.js作为模板引擎。任何人都知道如何使用underscore.js进行模板制作的好教程,特别是对于那些对高级javascript经验较少的biginner而言。谢谢


12
在“卢克”防御中,该手册的改进版本至少早在5月就没有高级用法
Shanimal

我刚刚回答了一个类似的问题,同样也会使您的问题受益。stackoverflow.com/questions/28136101/retrieve-column-in-parse/…–
jeffdill2

Answers:


475

您需要了解有关下划线模板的所有信息。仅需记住三件事:

  1. <% %> -执行一些代码
  2. <%= %> -在模板中打印一些值
  3. <%- %> -打印一些HTML转义的值

就是这样。

简单的例子:

var tpl = _.template("<h1>Some text: <%= foo %></h1>");

然后tpl({foo: "blahblah"})将呈现为字符串<h1>Some text: blahblah</h1>


55
我不明白为什么有人会反对票这一点,对项目的主页规范答案,并指向的指令,这是经典的“授人以鱼”。
Jon z'1

1
我认为他们会投反对票,因为他们提供的文档很少提供如何混合<%和<%=的示例,以及如何从<%=切换到print()改变该模式。同样,在使用“插值”时,有些奇怪的行为可能会使场景带有更多解释。再次,未提供。尽管我同意,但这是愚蠢的事情,但对票数不赞成。
QueueHammer 2012年

8
3. <%-%>-使用HTML转义来打印一些值
LeeGee 2012年

13
我没有投票,但是您的答案(除了提供链接之外)没有任何作用来解释如何使用underscore.js作为模板引擎。您的答案也许会为已经知道答案的人提供一个快速的“备忘单”,但就其本身而言,这并不是问题的答案。我很惊讶它的投票数和它一样多。
Zach Lysobey

1
-1,文档在许多方面都不足。几乎可以肯定,用户在查阅了文档之后就来到了这里。可怜的答案。
马特·帕金斯

198
<!-- Install jQuery and underscore -->

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>

<!-- Create your template -->
<script type="foo/bar" id='usageList'>
<table cellspacing='0' cellpadding='0' border='1' >
    <thead>
      <tr>
        <th>Id</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <%
        // repeat items 
        _.each(items,function(item,key,list){
          // create variables
          var f = item.name.split("").shift().toLowerCase();
      %>
        <tr>
          <!-- use variables -->
          <td><%= key %></td>
          <td class="<%= f %>">
            <!-- use %- to inject un-sanitized user input (see 'Demo of XSS hack') -->
            <h3><%- item.name %></h3>
            <p><%- item.interests %></p>
          </td>
        </tr>
      <%
        });
      %>
    </tbody>
  </table>
</script>

<!-- Create your target -->

<div id="target"></div>

<!-- Write some code to fetch the data and apply template -->

<script type="text/javascript">
  var items = [
    {name:"Alexander", interests:"creating large empires"},
    {name:"Edward", interests:"ha.ckers.org <\nBGSOUND SRC=\"javascript:alert('XSS');\">"},
    {name:"..."},
    {name:"Yolando", interests:"working out"},
    {name:"Zachary", interests:"picking flowers for Angela"}
  ];
  var template = $("#usageList").html();
  $("#target").html(_.template(template,{items:items}));
</script>
  • JsFiddle感谢@PHearst!
  • JsFiddle(最新)
  • 按首字母分组的JsFiddle List(带有图像,函数调用,子模板的复杂示例)将其分叉!尽情狂欢...
  • Xs hack的JsFiddle演示,下面由@tarun_telang指出
  • JsFiddle一种非标准方法来做子模板

17
感谢您在示例中明确使用“ text / html”脚本标签;我是underscore.js的新手,但我很不幸误读了文档-很高兴知道templateString不必总是内联编写。
aschyiel 2012年

模板实际上并不是在text/htmltype="text/html"谎言,谎言会引起问题。使用诸如的准确类型会更好text/x-underscore
亩太短了

6
亩,我想指出这一点很重要。面对现实吧,放任何东西都是骗人的。text / x-underscore是一个更大的谎言,因为我使用lodash,哈哈:)在上一个JsFiddle中,我添加了type="foo/bar"因为我希望每个人都知道只要浏览器/服务器不识别它并尝试就可以了用它做点事。由于html不是一种脚本,因此我对text / html感到很安全(John Resig使用它)foo / bar也可以使用:)
Shanimal 2013年

4
人们一直不同意我的观点,我会尽我最大的努力不让它成为个人(即使是个人的:)。一遍又一遍地被轻微的草率的意外副作用所困扰,我的习惯是在严格性方面犯了错误。MIME类型规范实际上保留了*/x-*用于“组合”用途的类型,我认为text/underscore官方注册表中没有类型,所以我使用它text/x-underscore是因为我很偏执,而且他们真的很想得到我。
亩太短

1
众所周知,XSS演示将不再起作用,因为浏览器拒绝使用错误的mimetype执行JS
nickford,

94

在最简单的形式中,您将像这样使用它:

var html = _.template('<li><%= name %></li>', { name: 'John Smith' });
//html is now '<li>John Smith</li>'   

如果您打算多次使用模板,则需要对其进行编译,以使其更快:

var template = _.template('<li><%= name %></li>');

var html = [];
for (var key in names) {
    html += template({ name: names[i] });
}

console.log(html.join('')); //Outputs a string of <li> items

我个人更喜欢Mustache风格的语法。您可以调整模板标记标记以使用双花括号:

_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;

var template = _.template('<li>{{ name }}</li>');

小胡子插值技巧对使用ejs渲染的express3视图有帮助。谢谢!
micrub 2014年

要从视图中使用模板,您可以在页面标记中包含以下内容:<script type =“ text / template” id =“ my-template”> <div> <%-name%> </ div> </ script >,然后在您的JS中执行以下操作:var html = _.template($('#my-template')。html(),{name:“ John Smith”}));
Gaurav Gupta 2014年

2
@evilcelery -你的interpolate小费没有工作,但这并:_.templateSettings = { interpolate: /\{\{\=(.+?)\}\}/g, escape: /\{\{\-(.+?)\}\}/g, evaluate: /\{\{(.+?)\}\}/g };
VSYNC

28

我看着源代码中的模板文档是不完整的。

_.template函数有3个参数:

  1. 字符串文本:模板字符串
  2. 对象数据:评估数据
  3. 对象设置:本地设置,_。templateSettings是全局设置对象

如果未提供任何数据(或null),则将返回渲染函数。它有1个参数:

  1. 对象数据:相同的数据上述

设置中有3种正则表达式模式和1种静态参数:

  1. RegExp 评估:模板字符串中的“ <%code%>”
  2. RegExp 插值:模板字符串中的“ <%= code%>”
  3. RegExp 转义:“ <%-code%>”
  4. 字符串变量:可选,模板字符串中数据参数的名称

评估部分中的代码将被简单地评估。您可以使用__p + =“ mystring”命令将本节中的字符串添加到评估的模板中,但是不建议这样做(不是模板接口的一部分),请使用插值部分代替。这种类型的部分用于向模板中添加诸如if或for之类的块。

插值部分中的代码结果将添加到评估的模板中。如果返回null,则将添加空字符串。

逃逸部分逃脱HTML与_.escape在给定的代码的返回值。因此,它的比类似_.escape(代码)中的内插部分,但它与逃逸\的空白字符等\ n它传递的代码到前_.escape。我不知道为什么这很重要,它在代码中,但是它与插值_.escape(也不能转义空白字符)一起很好地工作。

默认情况下,data参数是通过with(data){...}语句传递的,但是这种评估要比使用命名变量的评估慢得多。因此,使用变量参数命名数据是一件好事……

例如:

var html = _.template(
    "<pre>The \"<% __p+=_.escape(o.text) %>\" is the same<br />" +
        "as the  \"<%= _.escape(o.text) %>\" and the same<br />" +
        "as the \"<%- o.text %>\"</pre>",
    {
        text: "<b>some text</b> and \n it's a line break"
    },
    {
        variable: "o"
    }
);

$("body").html(html);

结果

The "<b>some text</b> and 
 it's a line break" is the same
as the "<b>some text</b> and 
 it's a line break" and the same
as the "<b>some text</b> and 
 it's a line break"

您可以在此处找到更多示例如何使用模板并覆盖默认设置:http : //underscorejs.org/#template

通过模板加载,您有很多选择,但是最后,您始终必须将模板转换为字符串。你可以把它作为像例如正常的字符串以上,或者你可以从一个脚本标签加载它,使用的.html()的jQuery的功能,也可以从与一个单独的文件中加载第三方物流插件require.js

使用简单的模板而不是模板来构建dom树的另一种选择。


21

我举一个非常简单的例子

1)

var data = {site:"mysite",name:"john",age:25};
var template = "Welcome you are at <%=site %>.This has been created by <%=name %> whose age is <%=age%>";
var parsedTemplate = _.template(template,data);
console.log(parsedTemplate); 

结果将是

Welcome you are at mysite.This has been created by john whose age is 25.

2)这是一个模板

   <script type="text/template" id="template_1">
       <% _.each(items,function(item,key,arr) { %>
          <li>
             <span><%= key %></span>
             <span><%= item.name %></span>
             <span><%= item.type %></span>
           </li>
       <% }); %>
   </script>

这是html

<div>
  <ul id="list_2"></ul>
</div>

这是包含json对象并将模板放入html的javascript代码

   var items = [
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       } 
   ];
  $(document).ready(function(){
      var template = $("#template_1").html();
      $("#list_2").html(_.template(template,{items:items}));
  });


14

用快递很简单。您需要做的就是在节点上使用整合模块,因此需要安装它:

npm install consolidate --save

那么您应该通过以下方式将默认引擎更改为html模板:

app.set('view engine', 'html');

为HTML扩展注册下划线模板引擎:

app.engine('html', require('consolidate').underscore);

完成 !

现在,例如,加载一个名为“ index.html”的模板:

res.render('index', { title : 'my first page'});

也许您需要安装下划线模块。

npm install underscore --save

希望对您有所帮助!


12

我想分享一个更重要的发现。

使用<%= variable =>将导致跨站点脚本漏洞。因此,使用<%-variable->代替更为安全。

我们必须将<%=替换为<%-以防止跨站点脚本攻击。不确定,这是否会对性能产生影响


2
+1我在示例中添加了有关XSS的注释。这是将未经消毒的用户信息注入网页的真正好处。通过模板引擎甚至$ .html()。
Shanimal

1

Lodash也一样首先写一个如下脚本:

<script type="text/template" id="genTable">
<table cellspacing='0' cellpadding='0' border='1'>
        <tr>
            <% for(var prop in users[0]){%>
            <th><%= prop %> </th>
            <% }%>
        </tr>
        <%_.forEach(users, function(user) { %>
            <tr>
                 <% for(var prop in user){%>
                    <td><%= user[prop] %> </td>
                <% }%>

            </tr>
        <%})%>
</table>

现在编写一些简单的JS,如下所示:

var arrOfObjects = [];
for (var s = 0; s < 10; s++) {
    var simpleObject = {};
    simpleObject.Name = "Name_" + s;
    simpleObject.Address = "Address_" + s;
    arrOfObjects[s] = simpleObject;
}
var theObject = { 'users': arrOfObjects }
var compiled = _.template($("#genTable").text());
var sigma = compiled({ 'users': myArr });

$(sigma).appendTo("#popup");

popoup是要在其中生成表的div

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.