是否可以从ko.computed函数访问绑定元素?
像这样的伪代码(为简洁起见而简化):
<h1 id="id1" data-bind="visible: myComputed">
<h1 id="id2" data-bind="visible: myComputed">
<h1 id="id3" data-bind="visible: myComputed">
...
self.myComputed = ko.computed(function(){
return <BOUND_ELEMNT>.id == 'id2';
});
仅导致显示的第二个元素。
注意:我知道我可以为每个元素分别计算,但在我的情况下是不可能的。
编辑:
好的 - 我会给出一个更准确的例子。以下内容与我的内容类似:
<section id="id1" data-bind="visible: myComputed1">A lot of code</section>
<section id="id2" data-bind="visible: myComputed2">different lots of code</section>
<section id="id3" data-bind="visible: myComputed3">Other lots of code</section>
...
// This field's value changes over time (between 'id1', 'id2' and 'id3').
// Some complex logic changes this field,
// and as a result only one h1 is showing at a time.
self.myField = ko.observable();
self.myComputed1 = ko.computed(function(){
return self.myField() == 'id1';
});
self.myComputed2 = ko.computed(function(){
return self.myField() == 'id2';
});
self.myComputed3 = ko.computed(function(){
return self.myField() == 'id3';
});
这是对DRY原则的丑恶违反,我想找到一种方法来重构它。上面的伪代码可以解决它,但我愿意接受建议......
答案 0 :(得分:3)
您已经创建了一个简短的简化示例,通常很棒。但是,感觉您已经引入了XY-problem。因此,这个答案可能有用也可能没用。
您尝试在 ViewModel 中引入对 View 的依赖关系。它应该是相反的方式!这样的事情会更有意义:
<h1 data-bind="visible: myComputed, attr { id: myId }"></h1>
请注意使用attr binding来设置ID。您的ViewModel应该相应地构建:
var activeHeaderId = 'id2';
var viewModel = function(id) {
var self = this;
self.myId = ko.observable(id);
self.myComputed = ko.computed(function() {
return self.myId() === activeHeaderId;
});
}
答案 1 :(得分:1)
注意:我将留下我的另一个答案作为问题第一点的答案,也许它会帮助其他用户绊倒这个问题。
更新中的问题是:
这是对DRY原则的丑恶违反,我想找到一种方法来重构它。
OP在评论中指出,关注给定示例的答案是首选。可以轻松地重构示例代码,使其不再违反DRY。 (PS。我仍然认为想要这种结构背后的“为什么”非常重要,但这并不妨碍我在给定样本的背景下回答这个问题。)
h1
- ViewModel中的一个项目使用以下视图:
<h1 data-bind="attr: {id: myField}">
使用此ViewModel:
self.myField = ko.observable();
非常干,在功能上几乎相同(除了其他2个h1
元素不仅是不可见的,它们甚至不在DOM中。)
h1
- ViewModel中的多个项目将视图重构为列表结构(请参阅foreach binding中的注释4):
<!-- ko foreach: items -->
<h1 data-bind="attr: {id: myId},
text: itemName,
visible: $root.currentItem().myId() === myId()">
</h1>
<!-- /ko -->
使用以下ViewModel:
var item = function(nr) {
this.itemName = ko.observable("Item number " + nr);
this.myId = ko.observable("id" + nr);
}
var viewModel = function() {
this.items = ko.observableArray([new item(1), new item(2), new item(3)]);
this.currentItem = ko.observable();
}
请参阅this fiddle了解演示。
h1
- ViewModel中的多个项目使用此方法,您可以使用类似于方法2中的设置的列表,但只渲染currentitem。视图使用with
binding:
<!-- ko with: currentItem -->
<h1 data-bind="attr: {id: myId}, text: itemName"></h1>
<!-- /ko -->
ViewModel与方法2中的相同。有关演示,请参阅this fiddle。
答案 2 :(得分:1)
创建一个自定义绑定处理程序,使用您的observable来触发可见性。像这样:
ko.bindingHandlers.idVisible = {
update: function(element, valueAccessor) {
var idUnwrapped = ko.utils.unwrapObservable(valueAccessor());
if(idUnwrapped == $(element).attr('id'))
{
$(element).show();
}
else
{
$(element).hide();
}
}
};
更改您的HTML:
<h1 id="id1" data-bind="idVisible: headerId">Header 1</h1>
<h1 id="id2" data-bind="idVisible: headerId">Header 2</h1>
<h1 id="id3" data-bind="idVisible: headerId">Header 3</h1>
示例视图模型:
function ViewModel() {
var self = this;
self.headerId = ko.observable('id1');
}
var vm = new ViewModel();
ko.applyBindings(vm);
这是一个带有演示的jsFiddle,它会在两秒后更改headerId:http://jsfiddle.net/psteele/cq9GU/