Underscore中的外部模板

我使用Underscore模板 。 可以附加一个外部文件作为模板

在骨干视图中我有:

textTemplate: _.template( $('#practice-text-template').html() ), initialize: function(){ this.words = new WordList; this.index = 0; this.render(); }, 

在我的HTML是:

 <script id="practice-text-template" type="text/template"> <h3>something code</h3> </script> 

它运作良好。 但是我需要外部模板 。 我尝试:

 <script id="practice-text-template" type="text/template" src="templates/tmp.js"> 

要么

 textTemplate: _.template( $('#practice-text-template').load('templates/tmp.js') ), 

要么

 $('#practice-text-template').load('templates/tmp.js', function(data){ this.textTemplate = _.template( data ) }) 

但它没有工作。

编辑:这个答案是旧的和过时的。 我会删除它,但这是“接受”的答案。 我会注入我的意见。

我不会主张这样做了。 相反,我会将所有模板分隔成单独的HTML文件。 有些人会build议asynchronous加载(Require.js或模板caching的sorting)。 这对于小型项目来说效果不错,但是在大型项目中有很多模板,你会发现自己在页面加载时会产生大量的exception请求,这是我真正不喜欢的。 (呃…好的,你可以通过使用r.js预编译你的初始依赖关系来解决Require.js的问题,但是对于模板来说,这仍然是我的错误)

我喜欢使用一个grunt任务(grunt-contrib-jst)将所有的HTML模板编译成一个templates.js文件并包含它。 你得到了最好的世界IMO …模板生活在一个文件,所述模板的编译发生在编译时(而不是运行时),并且当页面启动时,你没有一百个微小的asynchronous请求。

下面的一切都是垃圾

对我而言,我更喜欢使用我的模板包含JS文件的简单性。 所以,我可能会创build一个名为view_template.js的文件,其中包含模板作为variables:

 app.templates.view = " \ <h3>something code</h3> \ "; 

然后,就像包含脚本文件一样简单,然后在视图中使用它:

 template: _.template(app.templates.view) 

更进一步,我实际上使用了coffeescript,所以我的代码看起来更像这样,并避免了换行符:

 app.templates.view = ''' <h3>something code</h3> ''' 

使用这种方法避免了在require.js中实际上不需要的地方。

这是一个简单的解决scheme:

 var rendered_html = render('mytemplate', {}); function render(tmpl_name, tmpl_data) { if ( !render.tmpl_cache ) { render.tmpl_cache = {}; } if ( ! render.tmpl_cache[tmpl_name] ) { var tmpl_dir = '/static/templates'; var tmpl_url = tmpl_dir + '/' + tmpl_name + '.html'; var tmpl_string; $.ajax({ url: tmpl_url, method: 'GET', dataType: 'html', //** Must add async: false, success: function(data) { tmpl_string = data; } }); render.tmpl_cache[tmpl_name] = _.template(tmpl_string); } return render.tmpl_cache[tmpl_name](tmpl_data); } 

在这里使用“async:false”不是一个坏的方法,因为在任何情况下,你都必须等到模板被加载。

所以,“渲染”function

  1. 允许您将每个模板存储在静态目录中的单独的html文件中
  2. 是非常轻量级的
  3. 编译和caching模板
  4. 抽象模板加载逻辑。 例如,将来您可以使用预加载和预编译的模板。
  5. 很容易使用

[我在编辑答案,而不是留下评论,因为我认为这很重要。]

如果模板没有出现在本地应用程序中 ,并且您看到HIERARCHY_REQUEST_ERROR: DOM Exception 3 ,请查看Dave Robinson的回答究竟是什么会导致“HIERARCHY_REQUEST_ERR:DOMexception3” – 错误? 。

基本上,你必须添加

 dataType: 'html' 

到$ .ajax请求。

这个mixin允许你以非常简单的方式使用_.templateFromUrl(url, [data], [settings])渲染外部模板: _.templateFromUrl(url, [data], [settings]) 。 方法API几乎和Underscore _.template()一样 。 包括caching。

 _.mixin({templateFromUrl: function (url, data, settings) { var templateHtml = ""; this.cache = this.cache || {}; if (this.cache[url]) { templateHtml = this.cache[url]; } else { $.ajax({ url: url, method: "GET", async: false, success: function(data) { templateHtml = data; } }); this.cache[url] = templateHtml; } return _.template(templateHtml, data, settings); }}); 

用法:

 var someHtml = _.templateFromUrl("http://example.com/template.html", {"var": "value"}); 

我不想为这个简单的任务使用require.js,所以我使用了修改后的koorchik的解决scheme。

 function require_template(templateName, cb) { var template = $('#template_' + templateName); if (template.length === 0) { var tmpl_dir = './templates'; var tmpl_url = tmpl_dir + '/' + templateName + '.tmpl'; var tmpl_string = ''; $.ajax({ url: tmpl_url, method: 'GET', contentType: 'text', complete: function (data, text) { tmpl_string = data.responseText; $('head').append('<script id="template_' + templateName + '" type="text/template">' + tmpl_string + '<\/script>'); if (typeof cb === 'function') cb('tmpl_added'); } }); } else { callback('tmpl_already_exists'); } } require_template('a', function(resp) { if (resp == 'tmpl_added' || 'tmpl_already_exists') { // init your template 'a' rendering } }); require_template('b', function(resp) { if (resp == 'tmpl_added' || 'tmpl_already_exists') { // init your template 'b' rendering } }); 

为什么要将模板附加到文档中,而不是将它们存储在JavaScript对象中? 因为在生产版本中,我想生成所有模板已经包含的HTML文件,所以我不需要做任何额外的Ajax请求。 在同一时间,我不需要在我的代码中进行任何重构,就像我使用的那样

 this.template = _.template($('#template_name').html()); 

在我的骨干视图。

这可能有点偏离主题,但可以使用运行在node.js(http://nodejs.org/,可用于所有主要平台)的Grunt(http://gruntjs.com/)来运行命令行。; 这个工具有很多插件,比如模板编译器, https://npmjs.org/package/grunt-contrib-jst 。 请参阅GitHub上的文档, https://github.com/gruntjs/grunt-contrib-jst 。 (您还需要了解如何运行节点包pipe理器, https://npmjs.org/ 。别担心,它非常简单和多function。)

然后,您可以将所有的模板保存在不同的html文件中,使用下划线(我相信它是JST插件的依赖项,但不用担心,节点包pipe理器会自动为您安装依赖项)运行该工具来进行预编译。

这将所有的模板编译成一个脚本

 templates.js 

加载脚本会默认设置一个全局的“JST” – 这是一个函数数组,可以这样访问:

JST['templates/listView.html']()

这将是类似的

 _.template( $('#selector-to-your-script-template')) 

如果您将该脚本标记的内容放在(templates /)listView.html中

然而,真正的踢球者是这样的:Grunt带有这个叫'watch'的任务,它基本上监视你在本地grunt.js文件中定义的文件的变化(这基本上是你的Grunt项目的configuration文件,在JavaScript )。 如果您咕噜咕噜地为您启动此任务,请键入:

 grunt watch 

从命令行,Grunt会监视你对这些文件做出的所有更改,并在grunt.js文件中自动执行你已经为它设置的所有任务,如果它检测到变化的话 – 就像上面描述的jst任务一样。 编辑,然后保存你的文件,所有的模板重新编译成一个js文件,即使它们分布在多个目录和子目录中。

可以configuration类似的任务来testing你的javascript,运行testing,连接和缩小/丑化你的脚本文件。 所有可以绑定到监视任务,所以对文件的更改将自动触发您的项目的新“构build”。

这需要一些时间来设置和理解如何configurationgrunt.js文件,但是这非常值得投入时间,我不认为你会回到预先</s> way的工作方式

我认为这是对你有帮助的。 解决scheme中的所有内容都围绕着一个JavaScript文件和模块加载器require.js库进行。

上面链接的教程非常好地展示了一个骨干项目的组织方式。 还提供了一个示例实现 。 希望这可以帮助。

我对javascript模板感兴趣,现在我正在采取与骨干的第一步。 这是我想出来,似乎工作得很好。

 window.App = { get : function(url) { var data = "<h1> failed to load url : " + url + "</h1>"; $.ajax({ async: false, url: url, success: function(response) { data = response; } }); return data; } } App.ChromeView = Backbone.View.extend({ template: _.template( App.get("tpl/chrome.html") ), render: function () { $(this.el).html(this.template()); return this; }, }); App.chromeView = new App.ChromeView({ el : document.body }); App.chromeView.render(); 

我必须将数据types设置为“文本”才能使其适用于我:

 get : function(url) { var data = "<h1> failed to load url : " + url + "</h1>"; $.ajax({ async: false, dataType: "text", url: url, success: function(response) { data = response; } }); return data; } 

我使用jQueryfind了适用于我的解决scheme。

我使用jQuery.load()方法将下划线模板代码添加到主html文件。

一旦它在那里,我用它来生成模板。 都需要同步发生!

这个概念是:

我有一个下划线地图模板代码:

 <!-- MAP TEMPLATE--> <script type="text/template" id="game-map-template"> <% _.each(rc, function(rowItem, index){ %> <ul class="map-row" data-row="<%- index %>"> <li class="map-col <%- colItem.areaType ? 'active-area' : '' %>"></li> ... </script> 

我把这个代码放在一个名为map-template.html的文件中

之后,我创build了一个模板文件的包装。

 <div id="templatesPool"></div> 

然后,我将这个文件包含在我的主html文件中。

在头上:

 <!-- Template Loader --> <script> $(function(){ $("#templatesPool").append($('<div>').load("map-template.html")); }); </script> 

干杯。

我知道这个问题是非常古老的,但它出现在谷歌search的下一个ajax模板的第一个结果。

我厌倦了没有find一个好的解决scheme,所以我创build了自己的:

https://github.com/ziad-saab/underscore-async-templates

除了使用AJAX加载下划线模板外,它还添加了<%include%>function。 我希望对某人有用。

我有点不安,迫使jQuery同步工作,所以我修改了以前的同步使用promise的例子。 这几乎是一样的,但asynchronous运行。 我在这个例子中使用hbs模板:

 var asyncRenderHbs= function(template_name, template_data) { if (!asyncRenderHbs.template_cache) { asyncRenderHbs.template_cache= {}; } var promise= undefined; if (!asyncRenderHbs.template_cache[template_name]) { promise= new Promise(function(resolve, reject) { var template_url= '/templates/' + template_name; $.ajax({ url: template_url, method: 'GET', success: function(data) { asyncRenderHbs.template_cache[template_name]= Handlebars.compile(data); resolve(asyncRenderHbs.template_cache[template_name](template_data)); }, error: function(err, message) { reject(err); } }); }); } else { promise= Promise.resolve(asyncRenderHbs.template_cache[template_name](template_data)); } return promise; }; 

然后使用呈现的html:

 asyncRenderHbs('some_template.hbs', context) .then(function(html) { applicationMain.append(html); // Do other stuff here after html is rendered... }) .catch(function(err) { // Handle errors }); 

注意:正如其他人所讨论的,最好将所有模板编译成单个templates.js文件,并在开始时加载它,而不是在网页加载时有许多小的同步AJAX调用来获取模板。

前进警告 – 这里是龙:

我提到下面的方法只是为了帮助那些努力使ASP.NET栈(和类似的框架)与js-libs生态系统协调工作的人。 不言而喻,这不是一个通用的解决scheme。 话说回来 …

/ endforwardwarning

如果您正在使用ASP.NET,只需将它们放在一个或多个部分视图中,就可以将模板外化。 又名.cshtml里面:

  @Html.Partial("path/to/template") 

在你的template.cshtml里面:

  // this is razorview and thusly if you ever need to use the @ character in here // you will have to either escape it as @@ or use the html codepoint which is &#64 // http://stackoverflow.com/questions/3626250/escape-character-in-razor-view-engine <script type="text/x-template" id="someId"> <span class="foo"><%= name %></span> </script> 

现在,您可以像平常一样使用模板:

  _.template($("#someId").html())({ name: "Foobar" }); 

希望这种难以捉摸的方法可以帮助人们节省一个小时的头疼。