34

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

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)时,它不起作用。没有错误,它只是不会用数据替换标签。

有没有人遇到过这种情况或有任何解决方法?

谢谢!

4

7 回答 7

75

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

  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

于 2012-12-14T18:56:54.703 回答
33

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

上面的代码将在保留 {{..}} 标签的情况下呈现在客户端上。

于 2013-09-03T22:57:21.600 回答
14

是的,这是一个棘手的问题 --- 有点像 shell 脚本中的引用问题,它变成了引用引号的老鼠窝。

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

当然,jade 不是必需的(尽管它是为 expressjs 准备的)。您可以为服务器选择任何(非把手)模板引擎,和/或您可以在服务器上使用把手,在客户端上使用非把手模板 --- 只要您选择的模板引擎的两种语法不碰撞。由于我在客户端使用 emberjs 并且它使用把手语法(默认情况下),我更喜欢在客户端使用 emberjs + 把手语法。于是 expressjs +jade 成为了服务器的天作之合。

于 2012-04-06T08:19:23.270 回答
11

Shameless self-promotion!

I wanted to do this same client/server sharing thing, so I wrote a little npm package to assist:

node-handlebars-precompiler

I whipped it up in a couple hours based on the command-line compiler in wycats' handlebars repo. It's not the greatest code in the world, but it's been getting the job done for me very well.

EDIT: I am no longer maintaining this package. If you would like to take over, please contact me via Github. I mainly use Jade templates now, so it doesn't make sense for me to continue as the maintainer.

于 2012-04-23T20:52:21.393 回答
4

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

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

在您的路由处理程序中执行以下操作:

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 助手。

于 2012-07-14T08:30:39.060 回答
1

您有 2 个选项。第二个是最好的方法:

1)摆脱胡须

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

2) 预编译

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

于 2014-08-08T21:12:28.490 回答
1

我不喜欢预编译解决方案(因为我想在我将使用它们的同一个文件中定义模板)也不喜欢天真的\{{转义解决方案(因为它需要完整的 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
于 2016-02-20T01:44:19.850 回答