下划线中的外部模板

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

在 Backbone 视图中,我有:

 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>

It works well. But 我需要外部模板. 我试着:

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

但是没有成功。

80153 次浏览

我认为 这个可能对你有帮助。解决方案中的一切都围绕着 require.js库,它是一个 JavaScript 文件和模块加载器。

The tutorial at the link above shows very nicely how a backbone project could be organized. A 示例实现 is also provided. Hope this helps.

编辑: 这个答案既老又过时。我想删除它,但这是“接受”的答案。我会注入我的意见代替。

我不会再提倡这么做了。相反,我将把所有模板分成单独的 HTML 文件。有些人建议异步加载这些文件(Requre.js 或排序模板缓存)。这种方法在小型项目上运行良好,但是在有大量模板的大型项目上,您会发现自己在页面加载时发出了大量的小型异步请求,这是我非常不喜欢的。(uh... ok,你可以通过使用 r.js 预先编译你的初始依赖关系来绕过它,但是对于模板来说,我仍然觉得这是错误的)

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

下面的东西都是垃圾

对我来说,我更喜欢在模板中包含一个 JS 文件的简单性。因此,我可以创建一个名为 view _ template 的文件。Js 将模板作为变量包含在内:

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

然后,只需像普通脚本一样包含脚本文件,然后在视图中使用它:

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

更进一步,我的 事实上使用 coffee escript,所以我的代码实际上看起来更像这样,并且避免了行尾转义字符:

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

使用这种方法可以避免在实际上不需要的地方引入 Reque.js。

这里有一个简单的解决办法:

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

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

因此,“渲染”函数

  1. 允许您将每个模板存储在单独的 html 文件中的静态 导演
  2. is very lightweight
  3. 编译和缓存模板
  4. 抽象模板加载逻辑。例如,在将来,您可以使用预加载和预编译的模板。
  5. 很容易使用

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

如果模板没有出现在 本地应用程序,你看到的 HIERARCHY_REQUEST_ERROR: DOM Exception 3,看看答案由戴夫罗宾逊对 究竟什么会导致“ HIERARCHY _ REQUEST _ ERR: DOM 异常3”-错误?

基本上,你必须加上

dataType: 'html'

到 $. ajax 请求。

I got interested on javascript templating and now I'm taking the first steps with backbone. This is what i came up with and seems to work pretty well.

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

我不想在这个简单的任务中使用 Reque.js,所以我使用了修改过的 koorchik 解决方案。

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

在我的主干观点。

我必须将数据类型设置为“ text”才能让它为我工作:

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

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

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

这会将所有模板编译为一个脚本,比如

templates.js

加载脚本将设置一个全局(默认情况下是“ JST”) ,它是一个函数数组,可以这样访问:

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

类似于

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

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

然而,真正的关键是: Grunt 附带了一个名为“ watch”的任务,它基本上可以监视您在本地 Grunt.js 文件中定义的文件的更改(这基本上是您的 Grunt 项目的一个配置文件,在 javascript 中)。如果你已经咕噜咕噜地开始这项任务,输入:

grunt watch

在命令行中,Grunt 将监视您对文件所做的所有更改,如果它检测到更改,则自动执行在 Grunt.js 文件中为其设置的所有任务——如上面描述的 只是任务。编辑并保存文件,将所有模板重新编译为一个 js 文件,即使它们分散在许多目录和子目录中。

可以配置类似的任务来对 javascript 进行链接、运行测试、连接和缩小/丑化脚本文件。所有这些都可以绑定到监视任务,因此对文件的更改将自动触发项目的新“构建”。

设置和理解如何配置 grunt.js 文件需要花费一些时间,但是它非常非常值得投入时间,而且我认为您永远不会回到以前的工作方式

I know this question is really old but it came up as the first result on a google search for underscore ajax templates.

我厌倦了找不到解决这个问题的好办法,于是我创造了自己的办法:

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

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

This mixin allows you to render external template using 下划线 in very simple way: _.templateFromUrl(url, [data], [settings]). Method API is almost the same as 下划线的 _. template (). Caching included.

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

Usage:

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

强制 jQuery 同步运行让我有点不舒服,所以我使用承诺修改了前面的同步示例。它们几乎相同,但是是异步运行的。在这个例子中,我使用的是 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 生态系统协调工作的人。不用说,这不是一个通用的解决方案。话虽如此。

/结尾提示

如果您正在使用 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" });

希望这个难以捉摸的明显方法能帮助某人节省一个小时的挠头时间。

我找到了一个使用 jQuery 的解决方案。

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

一旦它存在,我就用它来生成模板。 All need to happen synchronously!

这个概念是:

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

<!-- 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的文件里

然后,我为模板文件创建一个包装器。

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

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

In head:

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

干杯。