143

我目前正在处理 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>

或者。

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

4

8 回答 8

226

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

于 2012-07-23T15:13:40.207 回答
19

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

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 助手接受一个类似 Ruby 的 arguments 散列。在帮助程序代码中,它们作为函数最后一个参数的一部分——<code>options——出现在其hash成员中。这样您就可以接收第一个参数——部分名称——然后获取数据。

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

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

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

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

于 2013-09-21T16:23:51.590 回答
15

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

/*///////////////////////

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) );
});
于 2013-01-31T03:38:38.113 回答
15

这也可以在更高版本的车把中使用以下key=value符号来完成:

 {{> mypartial foo='bar' }}

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

参考:部分#182的上下文不同

于 2014-10-08T15:28:44.447 回答
9

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

{{> 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 所说的那样成为部分的上下文 - 在那,它只看到 field another,但它看不到(或关心 field some)。如果你id在顶层模型中,并id在 childContext 中再次重复,那会很好,因为部分只看到里面的内容childContext

于 2014-11-04T19:56:46.470 回答
9

如果您只想在部分中使用不同的上下文,则接受的答案非常有用。但是,它不允许您引用任何父上下文。要传入多个参数,您需要编写自己的助手。这是 Handlebars 的工作助手2.0.0(另一个答案适用于版本<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>
于 2015-01-21T20:06:58.287 回答
3

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

于 2014-10-23T21:11:25.747 回答
2

不确定这是否有帮助,但这里有一个 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"}]' 
}}
于 2019-08-24T02:26:02.497 回答