服务器和客户端上带有 Handlebars.js 的 Node.js
Posted
技术标签:
【中文标题】服务器和客户端上带有 Handlebars.js 的 Node.js【英文标题】:Node.js with Handlebars.js on server and client 【发布时间】:2012-04-19 17:51:21 【问题描述】:我有一个使用 Expressjs 和 Handlebars 作为模板引擎的 Node.js 应用。
Expressjs 使用布局然后渲染视图。布局(layout.hbs)如下所示:
<!doctype html>
<html lang="en">
<head>
</head>
<body>
body
</body>
</html>
body
被替换为服务器端,在您访问路由时在 node.js 中。例如:
app.get('/', function(req, res)
res.render('index')
)
将body
标签替换为index.hbs的内容。
现在,在客户端,我正在使用 Backbone.js,并希望将 Handlebars 用于通过 Backbone 控制的视图。问题是因为这些页面已经通过 Handlebars 呈现,所以当我尝试在其中使用 Handlebars(或 Handlebars 中的 Handlebars)时,它不起作用。没有错误,它只是不会用数据替换标签。
有没有人遇到过这种情况或有任何解决方法的想法?
谢谢!
【问题讨论】:
【参考方案1】:您应该使用预编译的客户端模板。它们执行速度更快,允许您在服务器和客户端上使用相同的模板语言。
-
全局安装车把
npm install handlebars -g
预编译您的模板handlebars client-template1.handlebars -f templates.js
包含templates.js <script src="templates.js"></script>
执行模板var html = Handlebars.templates["client-template1"](context);
https://***.com/a/13884587/8360
【讨论】:
【参考方案2】:一个简单的方法是在 Handlebars 文件中的 之前附加一个
\
。例如:
<script type="text/x-template" id="todo-item-template">
<div class="todo-view">
<input type="checkbox" class="todo-checkbox" \checked>
<span class="todo-content" tabindex="0">\text</span>
</div>
<div class="todo-edit">
<input type="text" class="todo-input" value="\text">
</div>
<a href="#" class="todo-remove" title="Remove this task">
<span class="todo-remove-icon"></span>
</a>
上面的代码将在保留 .. 标签的情况下呈现在客户端上。
【讨论】:
真的吗?该死的,我希望我在一年前就知道这一点。这很好也很简单。 效果很好,我希望他们把它放在文档中......或者我只是错过了它。 非常感谢,我整个上午都在努力解决这个问题。【参考方案3】:是的,这是一个棘手的问题 --- 有点像 shell 脚本中的引用问题,它变成了引用引号的老鼠窝。
我的解决方案是在expressjs(服务器端)中使用jade(a la haml)为客户端输出基于把手的模板。这样,服务器使用一种语法(jade),而客户端使用另一种语法(handlebars)。我和你处在同一个十字路口,所以我面临着同样的挑战。
当然,jade 不是必需的(尽管它是为 expressjs 准备的)。您可以为服务器选择任何(非把手)模板引擎,和/或您可以在服务器上使用把手,在客户端上使用非把手模板——只要您选择的模板引擎的两种语法不碰撞。由于我在客户端使用 emberjs 并且它使用把手语法(默认情况下),我更喜欢在客户端使用 emberjs + 把手语法。于是 expressjs +jade 成为了服务器的天作之合。
【讨论】:
很公平,听起来我必须使用不同的模板引擎 - 谢谢! 虽然使用 Jade 似乎是解决方案,但我并不相信。如果您找到其他解决方案,我会很高兴...现在我相信使用 Jade 和 Angular.js 是我的解脱!【参考方案4】:无耻的自我推销!
我想做同样的客户端/服务器共享的事情,所以我写了一个小 npm 包来帮助:
node-handlebars-precompiler
我根据 wycats 的车把存储库中的命令行编译器在几个小时内完成了它。这不是世界上最棒的代码,但它已经很好地为我完成了工作。
编辑:我不再维护这个包。如果你想接手,请通过 Github 与我联系。我现在主要使用 Jade 模板,所以我继续作为维护者没有意义。
【讨论】:
【参考方案5】:我通过服务器端模板传递客户端模板来解决这个问题。
因此,在服务器端将所有客户端模板读取到一个数组中,并将其传递给服务器端的渲染函数
在您的路由处理程序中执行以下操作:
readTemplates(function(err, clientTemplates)
res.render("page",
clientTemplates: clientTemplates;
);
);
然后在 layout.hbs 中:
#each clientTemplates
<script type="text/handlebars id="this.filename" >
this.template
</script>
/each
这里我使用不带扩展名的文件名作为模板 ID,以便可以从 Backbone 视图中引用它们。哦,记得为生产模式实现缓存。
是的,这很糟糕。
我认为我们应该为此编写一个 Handlebars/Express/Connect 助手。
【讨论】:
【参考方案6】:您有 2 个选项。第二个是最好的方法:
1) 摆脱胡须
<script type="text/x-handlebars" data-hbs="example">
<p>\name</p>
</script>
2) 预编译
这将在发送到客户端之前在服务器上编译模板。这将使模板随时可用,并减轻浏览器的负担。
【讨论】:
【参考方案7】:我不喜欢预编译解决方案(因为我想在我将使用它们的同一个文件中定义模板)也不喜欢幼稚的\
转义解决方案(因为它需要完整的 Handlebars 编译器和更多的 javascript 代码)所以我想出了一个使用 Handlebars 助手的混合解决方案:
1) 在服务器配置中注册一个名为“模板”的新助手
var hbs = require('hbs');
hbs.registerHelper("template", function(key, options)
var source = options.fn().replace("\\", "");
var ret =
'<script>\n' +
key + ' = function(opt)\n' +
'return Handlebars.template(' + hbs.handlebars.precompile(source) + ')(opt);\n' +
'\n' +
'</script>';
return ret;
);
2) 在客户端网页的任何位置使用它(使用\
转义用于客户端参数)
#template "myTemplate"
<div>
<p>Hello \this.name!</p>
</div>
/template
(服务器会像这样预编译它)
<script>
myTemplate = function(opt)
return Handlebars.template(/* HBS PRECOMPILATED FUNCTION */)(opt);
</script>
3)只需在客户端javascript中调用您需要的函数
var generatedHtml = myTemplate("world"); // = <div><p>Hello world!</p></div>
$("#myDiv").html(generatedHtml); // or whatever
【讨论】:
以上是关于服务器和客户端上带有 Handlebars.js 的 Node.js的主要内容,如果未能解决你的问题,请参考以下文章
Handlebars的使用方法文档整理(Handlebars.js)