我有一个表,其中包含由foreach绑定生成的行。
与“通常”KO表的唯一区别是,对于行的动态筛选,我使用tr元素上的tr绑定,该绑定绑定到一个函数,该函数使用某些observables的值来决定当前行是否应该可见:
<table>
<thead>
...
</thead>
<tbody data-bind="foreach: unfilteredItems">
<tr data-bind="visible: $root.rowFilter($data)">
...
</tr>
</tbody>
</table>我之所以使用这种方法,是因为与传统的foreach绑定集合操作相比,它的性能要好得多,并导致不断插入\删除DOM节点。
这里唯一的问题是,没有纯粹的CSS解决方案来交替行的颜色。-- tr节点停留在DOM中,当某些tr不可见时,:nth-child()选择器不能正常工作。
因此,我不得不坚持使用jQuery解决方案:
function stripeVisibleRows(tableElem) {
var $visibleRows = $(tableElem).find('tr:visible');
$visibleRows.filter(':odd').css('background-color', '#EEEAE7');
$visibleRows.filter(':even').css('background-color', '#DED7D1');
};但是,当visible rowFilter 使用的任何可观测值触发更新 visible 绑定时,在执行绑定之后,如何才能在Knockout中调用该函数?
根据subscribe函数的不同,我尝试了一个假的computed:
self.rowFiltering = ko.computed(function () {
return self.rowFilter();
})
.subscribe(function () {
tableHelpers.stripeVisibleRows('.tbl');
});,编写这样的自定义绑定:
// Stripes visible tr elements.
// Must be applied to a table element.
// Must be bound to the same expression as used to change visibility of the tr elements.
ko.bindingHandlers.stripeVisibleRows = {
update: function (element, valueAccessor) {
// Read provided binding value to establish dependencies tracking
ko.utils.unwrapObservable(valueAccessor());
tableHelpers.stripeVisibleRows(element);
},
after: ['visible']
};以及它的用法:
<table data-bind="stripeVisibleRows: $root.rowFilter()">
<thead>
...
</thead>
<tbody data-bind="foreach: unfilteredItems">
<tr data-bind="visible: $root.rowFilter($data)">
...
</tr>
</tbody>
</table>但是使用这两种方法,我的jQuery条带函数在应用visible绑定之前都会被调用,因此不能正常工作。
,有人能建议我如何实现我想做的事情吗?
--也许我甚至需要改变整个过滤和条带行的方法--,但是它不应该插入\删除DOM节点,并且尽可能干净和可重用。
发布于 2015-09-24 21:52:57
你不得不在幕后做任何事情,只需要通过函数来揭露它。可以使用CSS类完成条带处理,因此您不需要担心使用jQuery。
因为数据项不会改变,所以它们只是一个不可观察的数组。在幕后,我们有一个基于rowFilter的计算,它可以访问一些可观察到的。foreach调用查看与当前项对应的计算中的项的函数,以设置可见性和类。
在本例中,您将根据元素的字母数对其进行过滤。
var tracker;
vm = {
letters: ko.observable(3),
unfilteredItems: ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'],
visible: function(idx) {
return tracker()[idx].visible;
},
odd: function(idx) {
return tracker()[idx].odd;
}
};
function rowFilter(item) {
return item.length === vm.letters();
}
tracker = ko.pureComputed(function() {
var visibleCount = 0;
var result = ko.utils.arrayMap(vm.unfilteredItems, function(item) {
var visible = rowFilter(item);
if (visible) ++visibleCount;
return {
visible: visible,
odd: visibleCount % 2
};
});
return result;
});
ko.applyBindings(vm);tr {
background-color: lightgreen;
}
tr.odd {
background-color: yellow;
}<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="value:letters, options:[3,4,5]"></select>
<table border="1">
<tbody data-bind="foreach: unfilteredItems">
<tr data-bind="visible: $root.visible($index()) , css: {odd:$root.odd($index())} ">
<td data-bind="text:$data"></td>
</tr>
</tbody>
</table>
发布于 2015-09-24 15:55:43
您可以订阅rowFilter的更改,然后推迟对stripeVisibleRows调用的执行,以确保模式已经更新了所有内容。
self.rowFilter.subscribe(function() {
setTimeout(function() {
tableHelpers.stripeVisibleRows('.tbl');
}, 0);
});对于不介意从DOM中删除/添加元素的情况,可以使用绑定而不是visible --这将完全从DOM中删除标记,而不只是隐藏它:
<table>
<thead>
...
</thead>
<tbody data-bind="foreach: unfilteredItems">
<tr data-bind="if: $root.rowFilter($data)">
...
</tr>
</tbody>
</table>发布于 2015-09-24 16:38:53
与其计算表呈现后的所有行条(即:使用stripeVisibleRows),不如将当前循环$index传递给一个单独的$root函数,让它确定该索引的当前条带是什么。例如:
Html:
<style>
.On { background-color: #CCC }
.Off { background-color: #FFF }
</style>
<table id='test'>
<thead>
...
</thead>
<tbody data-bind="foreach: unfilteredItems">
<tr data-bind="visible: IsVisible, css: $root.rowColour($index)">
<td data-bind='text: Text'></td>
</tr>
</tbody>
</table>Javascript:
var vmItem = function(visible, text) {
this.IsVisible = visible;
this.Text = text;
}
var vm = {
unfilteredItems: [
new vmItem(true, "Some"),
new vmItem(true, "Data"),
new vmItem(false, "Not Shown"),
new vmItem(true, "Shown"),
new vmItem(true, "To"),
new vmItem(false, "Blah!"),
new vmItem(true, "The User")
],
rowColour: function(index) {
var toggle = true;
for(var c = 0; c < index(); c++) {
// if the row at this index is visible, flip the row toggle
if (this.unfilteredItems[c].IsVisible) toggle = !toggle;
}
return toggle ? "On" : "Off";
}
};
ko.applyBindings(vm, $('#test')[0]);示例CodePen
https://stackoverflow.com/questions/32765718
复制相似问题