Knockout.js中为可观察数组对象添加属性并触发通知的更优方案
简化Knockout.js中展开/收起的UI更新实现
嘿,你的问题我完全get到了——原来用深克隆+replace的方式确实有点绕,完全可以通过让expanded成为可观察属性来简化,这样修改它的时候Knockout会自动帮你更新UI,根本不用手动调用replace。
咱们一步步来调整:
1. 让数组项的expanded成为ko.observable()
首先,别再用普通对象初始化observableArray了,给每个项创建带有可观察属性的结构就行。可以用一个简单的工厂函数来生成,这样每个item的expanded都是响应式的:
function MyViewModel() { var self = this; // 工厂函数:生成带有可观察属性的项 function createThing(id, anotherAttribute) { return { id: id, expanded: ko.observable(false), // 这里改成可观察属性 anotherAttribute: anotherAttribute }; } // 初始化数组,用工厂函数生成项 this.aThing = { theThings : ko.observableArray([ createThing(1, "someValue") ]) }; // 简化getMoreInfo:直接修改expanded的值 this.getMoreInfo = function(thing){ thing.expanded(true); // 直接设置为true,自动触发UI更新 }; // 对应的getLessInfo同理 this.getLessInfo = function(thing){ thing.expanded(false); }; }
2. 调整HTML绑定(几乎不用改!)
因为Knockout在if/ifnot绑定里会自动解包可观察属性,所以你的HTML代码几乎不用调整,直接用就行:
<div data-bind="foreach: aThing.theThings"> <div class="row"> <div class="col-md-12"> <!-- ko ifnot: expanded --> <i class="expander fa fa-plus-circle" data-bind="click: $parent.getMoreInfo"></i> <!-- /ko --> <!-- ko if: expanded --> <span data-bind="text: expanded()"/> <!-- 如果要显示值,需要加()手动解包 --> <i class="expander fa fa-minus-circle" data-bind="click: $parent.getLessInfo"></i> <!-- /ko --> <span data-bind="text: id"></span> (<span data-bind="text: anotherAttribute"></span>) </div> </div> </div>
为什么这样更简洁?
- 不用再做深克隆和
replace操作,代码量少了一大截 expanded是可观察属性,修改它的瞬间Knockout就会自动更新对应的UI元素- 逻辑更直观:点击图标→修改属性→UI自动刷新,完全符合Knockout的响应式设计理念
如果你的原始数据是从后端获取的普通对象,也可以遍历数组把每个对象的expanded转换成可观察属性,比如:
// 假设从后端拿到的原始数据 var rawThings = [{ id:1, expanded:false, anotherAttribute: "someValue" }]; // 转换为带有可观察属性的数组 self.aThing.theThings(rawThings.map(function(item) { item.expanded = ko.observable(item.expanded); return item; }));
这样就完美解决你的问题啦!
内容的提问来源于stack exchange,提问作者DrLazer
相关产品推荐
相关产品推荐

