【问题标题】:Node.js with Handlebars.js on server and client服务器和客户端上带有 Handlebars.js 的 Node.js
【发布时间】: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)时,它不起作用。没有错误,它只是不会用数据替换标签。

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

谢谢!

【问题讨论】:

    标签: javascript node.js handlebars.js express


    【解决方案1】:

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

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

    https://stackoverflow.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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-03-31
              • 1970-01-01
              • 2013-10-30
              • 2012-03-06
              • 2020-04-07
              • 2021-03-02
              相关资源
              最近更新 更多