根据此处给出的建议以及此处给出的有关如何为 forEach 制作自定义 bindingHandler 的信息,我决定尝试为 forEach 和 Masonry 编写自己的自定义绑定。
因为元素是动态添加的,所以不会发生重绘和移动元素以填充空间。所以,这个功能需要在元素被渲染之后移动或者在每个项目被添加之后被调用。
这是我的绑定处理程序
ko.bindingHandlers.masonry = {
init: function (element, valueAccessor, allBindingsAccessor) {
var $element = $(element),
originalContent = $element.html();
$element.data("original-content", originalContent);
//var msnry = new Masonry($element);
return { controlsDescendantBindings: true }
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
//get the list of items
items = value.items(),
//get a jQuery reference to the element
$element = $(element),
//get the current content of the element
elementContent = $element.data("original-content");
$element.html("");
var container = $element[0];
var msnry = new Masonry(container);
for (var index = 0; index < items.length; index++) {
(function () {
//get the list of items
var item = ko.utils.unwrapObservable(items[index]),
$childElement = $(elementContent);
ko.applyBindings(item, $childElement[0]);
//add the child to the parent
$element.append($childElement);
msnry.appended($childElement[0]);
})();
msnry.layout();
msnry.bindResize();
}
}
};
以及实现处理程序的 HTML。
<div id="criteriaContainer" data-bind="masonry: { items: SearchItems.Items }">
<div class="searchCriterion control-group">
<label class="control-label" data-bind="text: Description"></label>
<div class="controls">
<input type="hidden" data-bind="value: Value, select2: { minimumInputLength: 3, queryUri: SearchUri(), placeholder: Placeholder(), allowClear: true }" style="width: 450px">
</div>
<p data-bind="text: Value"></p>
</div>
</div>
当它显示在页面上时,如果通过 append 方法呈现的元素相互叠加,则它会堆叠所有元素。
您可以在我的 bindingHandler 中看到我正在调用 bindResize 以及 layout(),它们似乎都没有任何效果。
这是它在 UI 中的样子的屏幕截图。