Knockout.js 对于砌体的自定义绑定,如何适当调整容器的大小
基于给出的建议和关于如何为forEach创建自定义bindingHandler的信息,我决定尝试为forEach和forEach编写自己的自定义绑定 由于元素是动态添加的,因此不会重新绘制和移动元素以填充空间。因此,在呈现元素或添加每个项目后调用元素后,需要移动此功能 这是我的bindingHandlerKnockout.js 对于砌体的自定义绑定,如何适当调整容器的大小,knockout.js,jquery-masonry,bindinghandlers,Knockout.js,Jquery Masonry,Bindinghandlers,基于给出的建议和关于如何为forEach创建自定义bindingHandler的信息,我决定尝试为forEach和forEach编写自己的自定义绑定 由于元素是动态添加的,因此不会重新绘制和移动元素以填充空间。因此,在呈现元素或添加每个项目后调用元素后,需要移动此功能 这是我的bindingHandler ko.bindingHandlers.masonry = { init: function (element, valueAccessor, allBindingsAccessor) {
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();
}
}
};
ko.bindingHandlers.mashine={
init:function(元素、valueAccessor、allBindingsAccessor){
变量$element=$(element),
originalContent=$element.html();
$element.data(“原始内容”,原始内容);
//var msnry=新砌体($构件);
返回{ControlsDescentBindings:true}
},
更新:函数(元素、valueAccessor、allBindingsAccessor){
var value=ko.utils.unwrapobbservable(valueAccessor()),
//获取项目列表
items=值。items(),
//获取对元素的jQuery引用
$element=$(element),
//获取元素的当前内容
elementContent=$element.data(“原始内容”);
$element.html(“”);
var容器=$element[0];
var msnry=新砌体(容器);
对于(var索引=0;索引
以及实现处理程序的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中的屏幕截图。
我制作的定制活页夹基于其他人的同位素定制活页夹: 注:自定义同位素绑定的作者正在使用修改版的敲除。下面的绑定使用标准的敲除库(我使用的是v3.3.0) 让自定义绑定工作的诀窍是使用afterAdd回调跟踪添加的元素,以便将它们附加到砌体对象
"use strict";
(function () {
var $container, haveInitialized, newNodes = [], itemClass, masonryOptions;
function afterAdd(node, index, item) {
if (node.nodeType !== 1) {
return; // This isn't an element node, nevermind
}
newNodes.push(node);
}
ko.bindingHandlers.masonry = {
defaultItemClass: 'grid-item',
// Wrap value accessor with options to the template binding,
// which implements the foreach logic
makeTemplateValueAccessor: function (valueAccessor) {
return function () {
var modelValue = valueAccessor(),
options,
unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
options = {
afterAdd: afterAdd
};
// If unwrappedValue.data is the array, preserve all relevant
// options and unwrap value so we get updates
ko.utils.unwrapObservable(modelValue);
ko.utils.extend(options, {
'foreach': unwrappedValue.data,
'as': unwrappedValue.as,
'includeDestroyed': unwrappedValue.includeDestroyed,
'templateEngine': ko.nativeTemplateEngine.instance
});
return options;
};
},
'init': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
console.log({ msg: 'Initializing binding' });
itemClass = ko.bindingHandlers.masonry.defaultItemClass;
masonryOptions = {};
haveInitialized = false;
$container = $(element);
var parameters = ko.utils.unwrapObservable(valueAccessor());
if (parameters && typeof parameters == 'object' && !('length' in parameters)) {
if (parameters.masonryOptions) {
var clientOptions;
if (typeof parameters.masonryOptions === 'function') {
clientOptions = parameters.masonryOptions();
if (typeof clientOptions !== 'object') {
throw new Error('masonryOptions callback must return object');
}
} else if (typeof parameters.masonryOptions !== 'object') {
throw new Error('masonryOptions must be an object or function');
} else {
clientOptions = parameters.masonryOptions;
}
ko.utils.extend(masonryOptions, clientOptions);
}
if (parameters.itemClass) {
itemClass = parameters.itemClass;
}
}
// Initialize template engine, moving child template element to an
// "anonymous template" associated with the element
ko.bindingHandlers.template.init(
element,
ko.bindingHandlers.masonry.makeTemplateValueAccessor(valueAccessor)
);
return { controlsDescendantBindings: true };
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.template.update(element,
ko.bindingHandlers.masonry.makeTemplateValueAccessor(valueAccessor),
allBindingsAccessor, viewModel, bindingContext);
// Make this function depend on the view model, so it gets called for updates
var data = ko.bindingHandlers.masonry.makeTemplateValueAccessor(
valueAccessor)().foreach;
ko.utils.unwrapObservable(data);
if (!haveInitialized) {
masonryOptions.itemSelector = '.' + itemClass;
console.log({msg: 'Binding update called for 1st time, initializing Masonry', options: masonryOptions});
$container.masonry(masonryOptions);
}
else {
console.log({ msg: 'Binding update called again, appending to Masonry', elements: newNodes });
var newElements = $(newNodes);
$container.masonry('appended', newElements);
$container.masonry('layout');
newNodes.splice(0, newNodes.length); // reset back to empty
}
// Update gets called upon initial rendering as well
haveInitialized = true;
return { controlsDescendantBindings: true };
}
};
})();
以下是正在使用的绑定示例:
<div class="grid" data-bind="masonry: {data: blogEntries, masonryOptions: { itemClass: 'grid-item', columnWidth: 320, gutter: 10}}">
<div class="grid-item">
<div data-bind="css: {'idea-blog': isIdea }">
<img data-bind="attr: { src: imageUrl }">
<h2 data-bind="text: title"></h2>
<p data-bind="text: description"></p>
<div class="button-keep-reading">
<a data-bind="attr: { src: articleUrl }"><span data-bind="text: linkText"></span> ></a>
</div>
</div>
</div>
</div>
请注意,您需要确保在绑定数据之前加载在砌石平铺中使用的任何图像,因为砌石在其他方面存在布局问题