【问题标题】:Passing variables through handlebars partial通过车把部分传递变量
【发布时间】:2012-07-16 10:09:56
【问题描述】:

我目前正在处理 express.js 应用程序中的 handlebars.js。为了保持模块化,我将所有模板拆分为部分。

我的问题:我找不到通过部分调用传递变量的方法。假设我有一个看起来像这样的部分:

<div id=myPartial>
    <h1>Headline<h1>
    <p>Lorem ipsum</p>
</div>

假设我使用名称“myPartial”注册了这个部分。在另一个模板中,我可以这样说:

<section>
    {{> myPartial}}
</section>

这工作正常,部分将按预期呈现,我是一个快乐的开发人员。但是我现在需要的是一种通过此调用传递不同变量的方法,例如在部分中检查是否给出了标题。比如:

<div id=myPartial>
    {{#if headline}}
    <h1>{{headline}}</h1>
    {{/if}}
    <p>Lorem Ipsum</p>
</div>

调用应该如下所示:

<section>
    {{> myPartial|'headline':'Headline'}}
</section>

差不多。

我知道,在渲染模板之前,我能够定义我需要的所有数据。但我需要一种方法来做到这一点,就像刚才解释的那样。有没有可能的方法?

【问题讨论】:

    标签: javascript html handlebars.js templating


    【解决方案1】:

    Handlebars partials 采用第二个参数,该参数成为部分的上下文:

    {{> person this}}
    

    在 v2.0.0 alpha 及更高版本中,您还可以传递命名参数的哈希:

    {{> person headline='Headline'}}
    

    您可以查看针对这些场景的测试:https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462 https://github.com/wycats/handlebars.js/blob/e290ec24f131f89ddf2c6aeb707a4884d41c3c6d/spec/partials.js#L26-L32

    【讨论】:

    • 目前还不清楚这将如何应用于您的场景?您能否写下解决方案 - 请在您的情况下应用它?谢谢!
    • @Yehuda Katz 不是传入this,而是传入你自己的上下文。比如定义额外的数据传入,比如{new_variable: some_data}?
    • 虽然能够传入“this”很好,但这并不总是足够的。通常,您希望在同一页面上重用某个 html 片段,但如果部分具有 ID,您就注定要失败......同一个 ID 将多次出现并变得无效。如果您可以在调用它时将参数传递给partials,以进一步自定义其内容,那将非常有用。
    • Handlebars 的哪个版本支持这个?我使用的是 1.3.0,尝试通过 {{&gt; partialName {new_variable: some_data} }} 传递 json 时出现编译错误
    • @bafromca 这就是您不能传递任意数据而只能传递一个对象的确切问题。因此,您要么传递它,要么创建一个新属性,该属性在控制器或视图中返回您的 json-data。我认为应该可以以key=value 的形式将任意数据传递给部分数据。 github中是否有任何问题?
    【解决方案2】:

    如果您编写自己的助手,这是很有可能的。我们正在使用自定义的 $ 助手来完成这种类型的交互(以及更多):

    /*///////////////////////
    
    Adds support for passing arguments to partials. Arguments are merged with 
    the context for rendering only (non destructive). Use `:token` syntax to 
    replace parts of the template path. Tokens are replace in order.
    
    USAGE: {{$ 'path.to.partial' context=newContext foo='bar' }}
    USAGE: {{$ 'path.:1.:2' replaceOne replaceTwo foo='bar' }}
    
    ///////////////////////////////*/
    
    Handlebars.registerHelper('$', function(partial) {
        var values, opts, done, value, context;
        if (!partial) {
            console.error('No partial name given.');
        }
        values = Array.prototype.slice.call(arguments, 1);
        opts = values.pop();
        while (!done) {
            value = values.pop();
            if (value) {
                partial = partial.replace(/:[^\.]+/, value);
            }
            else {
                done = true;
            }
        }
        partial = Handlebars.partials[partial];
        if (!partial) {
            return '';
        }
        context = _.extend({}, opts.context||this, _.omit(opts, 'context', 'fn', 'inverse'));
        return new Handlebars.SafeString( partial(context) );
    });
    

    【讨论】:

    • 要访问传递的参数,您需要在“哈希”对象中查找它们:{{hash.foo}}。 (我是新手,这花了我一段时间才弄清楚) - 谢谢,好帮手!
    • 注意,这要求您在使用帮助程序之前预编译您的部分。我在 node.js 中使用 Handlebars,发现情况并非总是如此(部分是按需编译的)。我必须在加载后添加一个简单的帮助程序来预编译部分,然后这很好用!
    • @Dan 你有机会分享那个帮手吗? :)
    • @Tom,在这里(不知道如何正确格式化,抱歉):hbs.registerPartials(path.join(__dirname, '/views/partials'), function() { utils.precompileHandlebarsPartials(hbs); }); // Pre compile the partials precompileHandlebarsPartials : function(hbs) { var partials = hbs.handlebars.partials; for (var partial in partials) { if (typeof partials[partial] === 'string') { partials[partial] = hbs.handlebars.compile(partials[partial]); } }; }
    • @Dan 最好将其添加为自己的答案。
    【解决方案3】:

    以防万一,这就是我为获得部分参数所做的事情。我创建了一个小助手,它接受部分名称和将传递给部分的参数散列:

    Handlebars.registerHelper('render', function(partialId, options) {
      var selector = 'script[type="text/x-handlebars-template"]#' + partialId,
          source = $(selector).html(),
          html = Handlebars.compile(source)(options.hash);
    
      return new Handlebars.SafeString(html);
    });
    

    这里的关键是Handlebars helpers accept a Ruby-like hash of arguments。在帮助程序代码中,它们作为函数最后一个参数的一部分——options——在它的hash 成员中。通过这种方式,您可以接收第一个参数(部分名称)并获取之后的数据。

    然后,您可能希望从帮助程序返回 Handlebars.SafeString 或使用“triple‑stash”—{{{— 来防止它双重转义。

    这是一个或多或少完整的使用场景:

    <script id="text-field" type="text/x-handlebars-template">
      <label for="{{id}}">{{label}}</label>
      <input type="text" id="{{id}}"/>
    </script>
    
    <script id="checkbox-field" type="text/x-handlebars-template">
      <label for="{{id}}">{{label}}</label>
      <input type="checkbox" id="{{id}}"/>
    </script>
    
    <script id="form-template" type="text/x-handlebars-template">
      <form>
        <h1>{{title}}</h1>
        {{ render 'text-field' label="First name" id="author-first-name" }}
        {{ render 'text-field' label="Last name" id="author-last-name" }}
        {{ render 'text-field' label="Email" id="author-email" }}
        {{ render 'checkbox-field' label="Private?" id="private-question" }}
      </form>
    </script>
    

    希望这对……某人有所帮助。 :)

    【讨论】:

      【解决方案4】:

      这也可以在更高版本的车把中使用key=value 表示法完成:

       {{> mypartial foo='bar' }}
      

      允许您将特定值传递给您的部分上下文。

      参考:Context different for partial #182

      【讨论】:

      • 从 v2.0.0 alpha 版本开始提供此功能
      【解决方案5】:

      是的,我迟到了,但我可以为 Assemble 用户添加:您可以使用内置 "parseJSON" helper http://assemble.io/helpers/helpers-data.html。 (发现于https://github.com/assemble/assemble/issues/416)。

      【讨论】:

        【解决方案6】:

        听起来你想做这样的事情:

        {{> person {another: 'attribute'} }}
        

        Yehuda 已经为您提供了一种方法:

        {{> person this}}
        

        但要澄清:

        要为您的部分提供自己的数据,只需在现有模型中为其提供自己的模型,如下所示:

        {{> person this.childContext}}
        

        换句话说,如果这是您为模板提供的模型:

        var model = {
            some : 'attribute'
        }
        

        然后添加一个新对象给局部:

        var model = {
            some : 'attribute',
            childContext : {
                'another' : 'attribute' // this goes to the child partial
            }
        }
        

        childContext 成为部分的上下文,就像 Yehuda 所说的那样——它只看到字段 another,但看不到(或关心字段 some)。如果您在顶层模型中有 id,并在 childContext 中再次重复 id,那将正常工作,因为部分只能看到 childContext 内部的内容。

        【讨论】:

          【解决方案7】:

          如果您只想在部分中使用不同的上下文,则接受的答案非常有用。但是,它不允许您引用任何父上下文。要传入多个参数,您需要编写自己的助手。这是 Handlebars 2.0.0 的工作助手(另一个答案适用于版本 &lt;2.0.0):

          Handlebars.registerHelper('renderPartial', function(partialName, options) {
              if (!partialName) {
                  console.error('No partial name given.');
                  return '';
              }
              var partial = Handlebars.partials[partialName];
              if (!partial) {
                  console.error('Couldnt find the compiled partial: ' + partialName);
                  return '';
              }
              return new Handlebars.SafeString( partial(options.hash) );
          });
          

          然后在您的模板中,您可以执行以下操作:

          {{renderPartial 'myPartialName' foo=this bar=../bar}}
          

          在您的部分中,您将能够以上下文的形式访问这些值,例如:

          <div id={{bar.id}}>{{foo}}</div>
          

          【讨论】:

          • 我已经在 Handlebars 1.0.0 中试用过这个版本,它运行良好。
          • 在哪里“搜索”一个名为“...”的部分?
          【解决方案8】:

          不确定这是否有帮助,但这里有一个 Handlebars 模板示例,其中动态参数传递给内联 RadioButtons 部分,客户端(浏览器)呈现容器中的单选按钮。

          对于我的使用,它在服务器上使用 Handlebars 呈现,并让客户端完成它。 有了它,表单工具可以在 Handlebars 中提供内联数据而无需帮助。

          注意:此示例需要 jQuery

          {{#*inline "RadioButtons"}}
          {{name}} Buttons<hr>
          <div id="key-{{{name}}}"></div>
          <script>
            {{{buttons}}}.map((o)=>{
              $("#key-{{name}}").append($(''
                +'<button class="checkbox">'
                +'<input name="{{{name}}}" type="radio" value="'+o.value+'" />'+o.text
                +'</button>'
              ));
            });
            // A little test script
            $("#key-{{{name}}} .checkbox").on("click",function(){
                alert($("input",this).val());
            });
          </script>
          {{/inline}}
          {{>RadioButtons name="Radio" buttons='[
           {value:1,text:"One"},
           {value:2,text:"Two"}, 
           {value:3,text:"Three"}]' 
          }}
          

          【讨论】:

            猜你喜欢
            • 2014-06-24
            • 2016-12-01
            • 1970-01-01
            • 2016-07-20
            • 1970-01-01
            • 2015-08-26
            • 1970-01-01
            • 2016-07-21
            • 2013-11-17
            相关资源
            最近更新 更多