如何在Handlebars JS循环内修改父上下文变量?
我完全懂你碰到的这个坑——在Handlebars的each循环里想修改父级上下文的变量,但自定义的setVarWithName helper根本没起作用对吧?这问题其实出在上下文指向上,咱们一步步捋清楚怎么解决。
为什么你的代码没生效?
当你在{{#each questions}}块里调用helper时,this指向的是当前循环的单个question对象(也就是子上下文),而不是外层的根数据。所以你的this[name] = value其实是给每个question对象加了个test属性,完全没碰着父级的那个test变量,自然{{../test}}显示的还是原来的值。
正确的解决方法
要修改父级(或根)上下文的变量,得在helper里通过options参数拿到正确的上下文层级。Handlebars给helper提供了options.data.root(访问根数据对象)和options.parent(访问直接父级上下文)这两个关键属性,咱们用它们来定位目标上下文就行。
方案1:修改根上下文的变量
如果你的目标变量是在根数据里,直接用options.data.root来修改:
Handlebars.registerHelper('setVarWithName', function (name, value, options) { // 定位到根上下文并修改变量 options.data.root[name] = value; return ''; });
对应的模板里,推荐用{{@root.test}}来明确引用根变量(避免子上下文有同名变量时混淆):
{{setVarWithName "test" "hello"}} {{#each questions}} <h3>{{title}}</h3> <p>before update: {{@root.test}}</p> {{setVarWithName "test" "goodbye"}} <p>after update: {{@root.test}}</p> <hr /> {{/each}}
这样运行后,第一个循环的before显示hello,after变成goodbye;第二个循环的before直接就是goodbye了——因为根变量已经被修改,后续所有引用都会同步更新。
方案2:修改直接父级上下文的变量
如果你的变量不在根,而是在each的直接父级上下文里(比如嵌套循环的场景),就用options.parent来访问:
Handlebars.registerHelper('setParentVar', function (name, value, options) { // 修改直接父级上下文的变量 options.parent[name] = value; return ''; });
注意事项
Handlebars的上下文是基于数据对象的引用,所以修改父级/根变量会影响后续所有引用该变量的地方——这刚好符合你“在循环内修改变量并让后续生效”的需求,但如果是不想全局修改的场景,就得额外处理了。
内容的提问来源于stack exchange,提问作者shrewdbeans

