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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10037936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:35:40  来源:igfitidea点击:

Node.js with Handlebars.js on server and client

javascriptnode.jshandlebars.jsexpress

提问by dzm

I have an app in Node.js using Expressjs and Handlebars as the template engine.

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

Expressjs uses layouts and then renders views. The layout (layout.hbs) looks like this:

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

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

The {{{body}}}is replaced server-side, within node.js when you access a route. For example:

{{{body}}}当您访问路径被替换服务器端的node.js内。例如:

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

Will replace the {{{body}}}tag with the contents of index.hbs.

将用{{{body}}}index.hbs 的内容替换标签。

Now, on the client side I'm using Backbone.js and want to use Handlebars for the views controlled via Backbone. The problem is that because these pages are already rendered through Handlebars, when I attempt to use Handlebars within it (or Handlebars within Handlebars) it doesn't work. There are no errors, it simply just doesn't replace tags with data.

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

Has anyone encountered this before or have any idea a work around?

有没有人遇到过这个问题或有任何解决办法?

Thank you!

谢谢!

采纳答案by occam

Yup, it's a sticky problem --- kind of like the quoting problems in shell scripts which become a rats' nest of quoted quotes.

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

My solution is to use jade (a la haml) in expressjs (server-side) to output handlebars based templates for the client. This way, the server uses one syntax (jade), and the client uses another (handlebars). I am at the same crossroads as you, so I have the same challenge.

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

Of course, jade is not essential (though it's ready-made for expressjs). You could choose any (non-handlebars) template engine for the server, and/or you could use handlebars on the server with your non-handlebars templating on the client --- as long as the two syntaxes of your chosen templating engines do not collide. Since I'm using emberjs on the client and it uses handlebars syntax (by default), I prefer using emberjs + handlebars syntax on the client. So expressjs + jade became a natural fit for the server.

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

回答by Zachary Yates

You should use pre-compiled client templates. They are faster executing and allow you to use the same template language on the server and client.

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

  1. Install handlebars globally npm install handlebars -g
  2. Precompile your templates handlebars client-template1.handlebars -f templates.js
  3. Include templates.js <script src="templates.js"></script>
  4. Execute the template var html = Handlebars.templates["client-template1"](context);
  1. 全局安装车把 npm install handlebars -g
  2. 预编译您的模板 handlebars client-template1.handlebars -f templates.js
  3. 包含模板.js <script src="templates.js"></script>
  4. 执行模板 var html = Handlebars.templates["client-template1"](context);

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

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

回答by Tilo Mitra

An easy way to do this is to just append a \before the {{in a Handlebars file. For example:

一个简单的方法做,这是刚刚追加\{{的手把文件。例如:

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

The above code will be rendered on the client with the {{..}} tags preserved.

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

回答by Joel Wietelmann

Shameless self-promotion!

无耻的自我推销!

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

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

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.

我在几个小时内根据 wycats 的把手存储库中的命令行编译器进行了修改。它不是世界上最伟大的代码,但它为我完成了很好的工作。

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.

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

回答by Epeli

I have worked around this by passing client-side templates through server-side templates.

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

So on the server-side read all your client-side templates to an array and pass it to your render function on the server-side

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

In your route handler do something like:

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

readTemplates(function(err, clientTemplates) {
  res.render("page", {
    clientTemplates: clientTemplates;   
  });
});

And then in layout.hbs:

然后在 layout.hbs 中:

{{#each clientTemplates}}
<script type="text/handlebars id="{{this.filename}}" >
{{{this.template}}}
</script>
{{/each}}

Here I'm using file names without extensions as the template id so that they can be referenced from Backbone views. Oh, and remember to implement caching for production mode.

在这里,我使用没有扩展名的文件名作为模板 ID,以便可以从 Backbone 视图中引用它们。哦,记得为生产模式实现缓存。

Yeah, this sucks.

是的,这很糟糕。

I think we should write a Handlebars/Express/Connect helper for this.

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

回答by jordanb

You have 2 options. The second is THE best way to go:

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

1) Escape the mustaches

1)避开胡须

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

2) Precompile

2) 预编译

This will compile the template on the server before it goes to the client. This will make the template ready to use and reduces the burden on the browser.

这将在发送到客户端之前在服务器上编译模板。这将使模板随时可用并减少浏览器的负担。

回答by Oneiros

I didn't like the precompilation solution (because I want to define templates in the same file where I will use them) nor the naive \{{escape solution (because it needs the full Handlebars compiler and more javascript code) so I came up with an hybrid solution that uses Handlebars' helpers:

我不喜欢预编译解决方案(因为我想在我将使用它们的同一个文件中定义模板)也不喜欢简单的\{{转义解决方案(因为它需要完整的 Handlebars 编译器和更多的 javascript 代码)所以我想出了一个混合使用 Handlebars 助手的解决方案:

1) Register a new helper called "template" on server configuration

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) Use it anywhere in your client-side webpage (with \{{escape for client-side parameters)


2)在客户端网页的任何地方使用它(\{{客户端参数转义)

{{#template "myTemplate"}}
    <div>
        <p>Hello \{{this.name}}!</p>
    </div>
{{/template}}

(the server will precompile it in something like this)

(服务器会像这样预编译它)

<script>
    myTemplate = function(opt){
        return Handlebars.template(/* HBS PRECOMPILATED FUNCTION */)(opt);
    }
</script>


3) Simply call the function where you need it in client-side javascript


3)只需在客户端javascript中调用您需要的函数

var generatedHtml = myTemplate("world");   // = <div><p>Hello world!</p></div>
$("#myDiv").html(generatedHtml);           // or whatever