服务器和客户端上带有 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 &lt;script src="templates.js"&gt;&lt;/script&gt; 执行模板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.js 中缺少帮助程序

Django 模板中的 Handlebars.js

Handlebars的使用方法文档整理(Handlebars.js)

markdown 在使用AJAX呈现的Handlebars.js模板文件上显示平面JSON文件中的数据。

Handlebars.js模板

在 Handlebars.js 辅助参数中连接字符串和变量的合理方法?