underscore.js嵌套模板

时间:2012-01-20 08:55:20

标签: templates underscore.js

是否有可能以某种方式从下划线模板中获取DOM元素并将其用作另一个模板?

我的想法是我的应用需要呈现包含带有项目和摘要的循环的文档。我需要偶尔重新渲染摘要或一些项目,所以我不能只重新渲染整个文档。

但是,我想让应用程序用户为文档创建自己的模板很简单,我认为将所有内容保存在一个文件中会使文档更容易。

我正在尝试使用这样的东西:

<script type="text/template" id="document-template">
    <div id="document">
        <h1><%= name %></h1>
        <ul class="items">
            <% _.each(items, function(item) { %> 
                <li><%= item %></li>
            <% }); %>
        </ul>
        <div id="summary">
            <p>Total items: <%= totalitems %></p>
        </div>
    </div>
</script>

现在,我可以轻松地将此变量documentTemplate = _.template($('#document-template').html());转换为文档模板,但我想将摘要部分转换为模板,将列表项转换为模板。

我可以这样做:

var summaryTemplate = _.template($('#document-template #summary').html());
var itemTemplate = _.template($('#document-template .items li').html());

PS。实际上我正在使用jQuery的$ .get从外部文件加载模板。这样我就可以将文档模板放在一个大字符串中。从那里开始,我只能做documentTemplate = _.template(loadedString);

现在,如果我可以从字符串中提取#summary元素,它应该可以工作。但是当我尝试将字符串转换为DOM元素(var domElement = $(loadedString))时 (所以我可以这样做:summaryTemplate = _.template($('#summary',domElement).html());,它不起作用,因为下划线将不再识别&lt;%=%&gt;标记了。

4 个答案:

答案 0 :(得分:65)

您可以将嵌套模板作为模板分配中的变量传递给主模板,例如:

HTML:

<script type="text/template" id="sub_template">
  <article>
    <h1>id: <%= id %><h1>
  </article>
</script>

<script type="text/template" id="main_template">
  <% for (var i = 0; i < num; i++) { %>
    <%= renderSub({id:i}) %>
  <% } %>
</script>

JS:

 var renderSub = _.template( $('#sub_template').remove().text() ),
     renderMain = _.template( $('#main_template').remove().text() );

  renderMain({num:5, renderSub:renderSub});

答案 1 :(得分:5)

Playground

/////// TEMPLATES //////

    var mainTemplate = "<ul> \
                          <% _.each(items, function(item) { %> \
                               <%= listItem({item:item}) %> \
                          <% }); %> \
                        <ul>";

    var subTemplate = '<li><%=item %></li>';


/////// MODEL (our data) //////

    var model = {
        items : [1,2,3,4,5]
    }


/////// COMPILE //////

    // add the subTemplate to the model data, to be passed to the mainTemplate
    model.listItem = _.template(subTemplate);

    // Render main template to the DOM
    document.body.innerHTML = _.template(mainTemplate, model);

答案 2 :(得分:2)

不是一次性将所有内容作为一个模板加载,然后再尝试再次加载它的一部分,而是将它们分隔为多个模板。

拥有主文档模板和摘要模板。初始加载拉入文档模板,然后拉入摘要模板并将其从第一个模板插入到编译的DOM中。然后您可以随时重新加载第二个模板。请参阅以下步骤:

1)加载初始模板,如下所示:

<script type="text/template" id="document-template">
    <div id="document">
        <h1><%= name %></h1>
        <ul class="items">
            <% _.each(items, function(item) { %> 
                <li><%= item %></li>
            <% }); %>
        </ul>
    </div>
</script>

2)一旦将其编译到DOM中,通过下划线加载第二个模板,如下所示:

<script type="text/template" id="summary-template">
    <div id="summary">
        <p>Total items: <%= totalitems %></p>
    </div>
</script>

3)调用$(“#document”)。append(summaryTemplate),或者保存编译模板的任何变量。

4)在您需要重新加载摘要时重复步骤2和3,除非先删除现有的$(“#summary”),然后再追加

您也可以对项目使用相同的策略,只需确保使用正确的jQuery选择器/方法,以便以正确的顺序覆盖现有的div,因为append只适用于向元素的结尾。

答案 3 :(得分:1)

我知道我对话的时间已经晚了3年,但这些答案都没有适用于我在最新项目中遇到的情况。而且由于我最初考虑这样做的方式最终起作用,我想我应该发布它,以防其他人想要实际嵌套underscore.js模板,正如这个问题的标题所述。

我的要求基本上是:

  

1)如果模板中有动态部分,它们应该能够单独重新渲染自己 - 而不需要使用更新的数据重新渲染整个模板。

     

2)动态部分不需要在与父模板相同的级别上分裂成自己的模板;相反,应该有一种模板层次结构 - 一个模板,声明自身所需的所有子模板。

Underscore.js中嵌套模板的概念与PHP中的相同(例如)。以下代码是“回显PHP”的示例:

<?php echo '<?php echo $var_unknown_until_runtime; ?>'; ?>

虽然这种嵌套语法可能会令人费解并且令人困惑,但这个想法很简单:

  

稍后将回显值的回声代码。

这也适用于Underscore.js模板。

实施例

代码如下所示:

<script type="text/template" id="outer-tpl">
    <%= value %>

    <script type="text/template" id="inner-tpl">
        <%= '<%= value %\>' %> <!-- NOTE how the inner '>' is escaped ('\>') -->
    <%= "</script\>" %> <!-- NOTE same thing -->
</script>

让我们稍微打破一下。第一个NOTE的行是我们的关键行。通常,当Underscore编译此模板时,您可能希望在外部和内部模板中打印value的值。我们做了一些事情来防止这种情况发生:

  

1)将嵌套的下划线语句转换为字符串。

     

2)插入该字符串(<%= "string here" %>)。

     

3)在嵌套的下划线语句(>)中转义结束\>。这可以防止Underscore的正则表达式与步骤2中的开始标记(<%=)匹配。当回显此字符串时,将删除转义字符,留下%>,准备在下一次通过时由Underscore解释。

在我们示例中的第二个NOTE中执行相同的操作会阻止浏览器结束第一个script标记。技术上不允许使用嵌套的script标记,因此浏览器会查找第一个字符序列:</script>,然后结束脚本执行。这会阻止浏览器识别此序列。

有关更深入的示例,请参阅此JSFiddle

免责声明

我并不认为这是接近做这种事情的最佳方式。毕竟,它非常hacky。虽然@John z的答案打破了我的第一个要求,这对我来说不是一个选项,但是将模板中的动态部分拆分成自己的模板的另一个选择可能更容易处理。它的组织性较差。

DOM中所有这些嵌套script标记的位置很难跟踪(因为嵌套的script标记会在插入外部模板时随时随地动态注入DOM )。重复的风险很高,维护起来很烦人。

嵌套模板的难度对于每个嵌套级别都会大幅增加(要将模板嵌套在嵌套模板中,您必须再次逃避所有内容等等)。小提琴包括一个例子。