在服务器和客户端上使用Handlebars.js的Node.js

我在Node.js中有一个应用程序,使用Expressjs和Handlebars作为模板引擎。

Expressjs使用布局,然后呈现视图。 布局(layout.hbs)如下所示:

<!doctype html> <html lang="en"> <head> </head> <body> {{{body}}} </body> </html> 

当你访问一个路由时, {{{body}}}被replace为node.js中的服务器端。 例如:

 app.get('/', function(req, res){ res.render('index'}) }) 

将用index.hbs的内容replace{{{body}}}标记。

现在,在客户端,我使用Backbone.js,并希望使用Handlebars来控制通过Backbone控制的视图。 问题是,因为这些网页已经通过把手呈现,所以当我尝试使用其中的把手(或把手内的把手)时,它不起作用。 没有错误,它只是不会用数据replace标签。

有没有人遇到过这个或有任何想法的工作?

谢谢!

是的,这是一个棘手的问题 – 有点像shell脚本中的引用问题,变成老鼠引用引语。

我的解决scheme是在expressjs(服务器端)中使用jade(la haml)为客户端输出基于句柄的模板。 这样,服务器使用一种语法(玉),而客户端使用另一种(句柄)。 我和你在同一个十字路口,所以我有同样的挑战。

当然,翡翠并不是必不可less的(尽pipe它已经为expressjs准备好了)。 您可以为服务器select任何(非句柄)模板引擎,并且/或者您可以使用客户端上的非句柄模板在服务器上使用句柄—只要您select的模板引擎的两种语法不碰撞。 由于我在客户端上使用了emberjs,并且它使用了handlebars语法(默认情况下),所以我更喜欢在客户端上使用emberjs + handlebars语法。 所以expressjs + jade成了服务器的天作之合。

您应该使用预编译的客户端模板。 它们的执行速度更快,并允许您在服务器和客户端上使用相同的模板语言。

  1. 安装全局的npm install handlebars -g
  2. 预编译你的模板handlebars client-template1.handlebars -f templates.js
  3. 包含templates.js <script src="templates.js"></script>
  4. 执行模板var html = Handlebars.templates["client-template1"](context);

https://stackoverflow.com/a/13884587/8360

一个简单的方法就是在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> 

上面的代码将在客户端上保存{{..}}标签。

无耻的自我推销!

我想做同样的客户端/服务器共享的事情,所以我写了一个小小的npm包来协助:

节点车把-预编译器

基于wycats的handlebars回购中的命令行编译器,我在几个小时内就把它搞砸了。 这不是世界上最伟大的代码,但它已经为我完成了很好的工作。

编辑:我不再维护这个包。 如果您想接pipe,请通过Github与我联系。 我现在主要使用Jade模板,所以我继续作为维护者是没有意义的。

我通过通过服务器端模板传递客户端模板来解决这个问题。

所以在服务器端读取所有的客户端模板到一个数组,并将其传递给服务器端的渲染函数

在你的路由处理程序中做一些事情:

 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视图中引用。 哦,并记住为生产模式实施caching。

是的,这很糟糕。

我想我们应该为此写一个Handlebars / Express / Connect助手。

你有2个选项。 第二是最好的方式去:

1)逃出胡须

 <script type="text/x-handlebars" data-hbs="example"> <p>\{{name}}</p> </script> 

2)预编译

这将在服务器上编译模板到客户端之前。 这将使模板准备好使用并减轻浏览器的负担。

我不喜欢预编译的解决scheme(因为我想在我将使用它们的同一个文件中定义模板),也不喜欢天真的\{{逃生解决scheme(因为它需要完整的Handlebars编译器和更多的JavaScript代码),所以我来了使用Handlebars的助手的混合解决scheme:

1)在服务器configuration上注册一个名为“template”的新帮手

 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)在客户端网页的任何地方使用它(用\{{ escape for client-side parameters)

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