Knockout虚拟元素foreach循环上下文丢失:无法访问Value.SpecificValue
这是Knockout中上下文切换导致的典型问题,我来给你捋清楚:
核心原因:foreach会改变绑定上下文
当你在模板中直接写 <label data-bind="text: Value.SpecificValue"></label>(如果根绑定对象就是Value,直接写SpecificValue也能正常工作),此时绑定的上下文是整个Value对象,所以能直接访问它的SpecificValue属性。
但当你进入<!-- ko foreach: Value.List -->虚拟元素后,Knockout会把绑定上下文切换为List数组中的每一个子项(也就是每个{Name, Value}对象)。这时候如果你再直接写Value.SpecificValue,Knockout会在当前子项对象里找Value属性——而子项只有Name和自身的Value属性(和根对象的SpecificValue是完全不同的东西),自然找不到你要的目标属性。
解决办法:指定外部上下文
你可以通过Knockout提供的上下文关键字来访问外部的Value对象,常用的几种方式:
使用
$parent关键字
如果foreach是直接在根上下文(Value对象)下使用的,$parent就代表根对象。写法如下:<label data-bind="text: SpecificValue"></label> <!-- 正常工作 --> <!-- ko foreach: List --> <div> <!-- 用$parent访问根对象的SpecificValue --> <span data-bind="text: $parent.SpecificValue"></span> <span data-bind="text: Name"></span> <span data-bind="text: Value"></span> <!-- 子项自身的Value属性 --> </div> <!-- /ko -->使用
$root关键字
如果你的模板有多层嵌套(比如foreach里还有foreach),$parent可能会指向中间层的上下文,这时候用$root更稳妥——它始终代表最顶层的绑定对象(也就是你的Value对象):<!-- ko foreach: List --> <div> <span data-bind="text: $root.SpecificValue"></span> </div> <!-- /ko -->用
let绑定给上下文起别名(Knockout 3.5+)
如果你觉得$parent/$root不够直观,可以用let绑定给根对象起一个别名,在整个块内都能直接使用:<!-- ko let: rootValue = $root --> <label data-bind="text: rootValue.SpecificValue"></label> <!-- ko foreach: rootValue.List --> <div> <span data-bind="text: rootValue.SpecificValue"></span> </div> <!-- /ko --> <!-- /ko -->
额外提醒
注意子项里的Value属性和根对象的SpecificValue是不同的属性,虽然你说它们的值匹配,但绑定的时候Knockout只会看属性名,别搞混啦~
内容的提问来源于stack exchange,提问作者dafna

