gpt4 book ai didi

javascript - 如何在 knockout 中向可观察数组中的对象添加属性并触发通知?

转载 作者:行者123 更新时间:2023-12-03 02:43:55 25 4
gpt4 key购买 nike

使用 Knockout.js,我的 View 模型中有一个可观察数组。

function MyViewModel() {
var self = this;

this.getMoreInfo = function(thing){
var updatedSport = jQuery.extend(true, {}, thing);
updatedThing.expanded = true;
self.aThing.theThings.replace(thing,updatedThing);
});
}

this.aThing = {
theThings : ko.observableArray([{
id:1, expanded:false, anotherAttribute "someValue"
}])
}
}

然后我有一些 html,它们会根据名为“expanded”的属性的值而改变。它有一个可点击的图标,应该将 Expanded 的值从 false 切换为 true(有效更新图标)

<div data-bind="foreach: aThing.theThings">
<div class="row">
<div class="col-md-12">
<!-- ko ifnot: $data.expanded -->
<i class="expander fa fa-plus-circle" data-bind="click: $parent.getMoreInfo"></i>
<!-- /ko -->
<!-- ko if: $data.expanded -->
<span data-bind="text: $data.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: name"></span>)
</div>
</div>
</div>

看看我为了更新 html 而在 getMoreInfo() 函数中编写的怪物。我在 knockout 中使用 observableArrays 上的 Replace() 函数,这将强制向所有订阅的对象发出通知。仅当两个参数不是同一对象时,replace() 才会起作用。因此,我使用 jQuery 深度克隆来复制对象并更新属性,然后这会反射(reflect)到标记上。我的问题是......有没有更简单的方法来实现这一目标?

出于这个问题的目的,我稍微简化了我的代码片段。在用户对应用程序执行特定操作之前,“扩展”属性实际上并不存在。它是动态添加的,本身不是可观察的属性。我尝试单独在这个属性上调用 ko.observable() ,但它并没有阻止在 observable 数组上调用 Replace() 来刷新 UI 的需要。

最佳答案

Knockout 最适合具有动态属性和事件处理程序的模型由 View 模型支持的架构。

通过构建 View 模型Thing,您可以极大地提高代码的质量和可读性。这是一个例子。请注意模板(= View )变得更加清晰。

function Thing(id, expanded, name) {
// Props that don't change are mapped
// to the instance
this.id = id;
this.name = name;

// You can define default props in your constructor
// as well
this.anotherAttribute = "someValue";

// Props that will change are made observable
this.expanded = ko.observable(expanded);

// Props that rely on another property are made
// computed
this.iconClass = ko.pureComputed(function() {
return this.expanded()
? "fa-minus-circle"
: "fa-plus-circle";
}, this);
};

// This is our click handler
Thing.prototype.toggleExpanded = function() {
this.expanded(!this.expanded());
};

// This makes it easy to construct VMs from an array of data
Thing.fromData = function(opts) {
return new Thing(opts.id, opts.expanded, "Some name");
}



function MyViewModel() {
this.things = ko.observableArray(
[{
id: 1,
expanded: false,
anotherAttribute: "someValue"
}].map(Thing.fromData)
);
};

MyViewModel.prototype.addThing = function(opts) {
this.things.push(Thing.fromData(opts));
}

MyViewModel.prototype.removeThing = function(opts) {
var toRemove = this.things().find(function(thing) {
return thing.id === opts.id;
});

if (toRemove) this.things.remove(toRemove);
}

var app = new MyViewModel();
ko.applyBindings(app);

// Add stuff later:
setTimeout(function() {
app.addThing({ id: 2, expanded: true });
app.addThing({ id: 3, expanded: false });
}, 2000);

setTimeout(function() {
app.removeThing({ id: 2, expanded: false });
}, 4000);
.fa { width: 15px; height: 15px; display: inline-block; border-radius: 50%; background: green; }
.fa-minus-circle::after { content: "-" }
.fa-plus-circle::after { content: "+" }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div data-bind="foreach: things">
<div class="row">
<div class="col-md-12">
<i data-bind="click: toggleExpanded, css: iconClass" class="expander fa"></i>
<span data-bind="text: id"></span> (
<span data-bind="text: name"></span>)
</div>
</div>
</div>

关于javascript - 如何在 knockout 中向可观察数组中的对象添加属性并触发通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48189478/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com