underscore.js嵌套模板

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

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

不过,我希望应用程序用户能够简单地为文档创build自己的模板,我认为将所有内容保存在一个文档中可以使文档更容易。

我试图使用这样的东西:

<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> 

现在,我可以很容易地做这个var documentTemplate = _.template($('#document-template').html()); 把它变成一个文档模板,但我想把摘要部分变成模板和列表项目。

我可以做这样的事情吗?

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

PS。 实际上,我使用jQuery的$ .get从外部文件加载模板。 这样,我将得到一个大string的文档模板。 从那里,我可以做documentTemplate = _.template(loadedString);

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

您可以将嵌套模板作为模板赋值中的variables传递给主模板,例如:

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}); 

操场

 /////// 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); 

而不是一次加载一个模板,然后尝试再次加载一部分,将它们分成多个模板。

有你的主要文件模板和摘要模板。 初始的负载拉入文档模板,然后拉入摘要模板并将其插入到第一个模板的编译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)或其他variables持有已编译的模板。

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

您也可以对这些项目使用相同的策略,只要确保使用了正确的jQueryselect器/方法,以便以正确的顺序覆盖现有的div,因为append只能用于将某些内容添加到元件。

我知道我谈话迟了3年,但是这些答案根本不适用于我最近的项目。 而且由于我最初想这样做的方式最终导致了工作,所以我想我应该发布它,以防其他人想要嵌套underscore.js模板,正如这个问题的标题所述。

我的要求基本上是:

1)如果模板中有dynamic片段,它们应该能够单独重新呈现自己,而不需要使用更新的数据重新呈现整个模板。

2)dynamic片段不需要在与父模板相同的层次上被拆分成自己的模板; 相反,应该有一种模板层次结构 – 一个模板,用来声明自己需要的所有子模板。

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是我们的重点。 通常当下划线编译这个模板时,你会希望在外部和内部模板中都打印值的value 。 我们做了一些事情来防止这种情况发生:

1)将嵌套的下划线语句转换为string。

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

3)在嵌套的下划线语句( \> )中退出closures> 。 这可以防止Underscore的正则expression式将它与步骤2( <%= )中的开始标记进行匹配。 当这个string被回显时,转义字符将被删除,留下%> ,准备在下一个回合中被Underscore解释。

在我们的例子中,在第二个NOTE中做同样的事情可以防止浏览器结束第一个script标记。 技术上嵌套的script标记是不允许的,所以浏览器查找第一个字符序列: </script> ,然后结束脚本执行。 这阻止浏览器识别这个序列。

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


免责声明

我不认为这是最好的方式来做这种事。 毕竟,这是非常黑客。 虽然@John z的回答打破了我的第一个要求,这对我来说不是一个select,但将模板中的dynamic片断分解到自己模板中的另一种select可能更容易处理。 这只是less组织。

所有这些嵌套的script标签在您的DOM中的位置可能难以追踪(因为embedded的script标签将在您插入外部模板时插入到DOM中)。 重复的风险很高,并且可能很烦人。

嵌套模板的难度大大增加了每一层的嵌套(嵌套嵌套模板中的模板,你必须再次逃避一切,等等…)。 小提琴包括一个这样的例子。