无论何时您需要更改DOM,您都应该尝试通过敲除数据绑定来完成此操作。大部分可以通过敲除的默认绑定来完成;有些东西需要自定义绑定。
对于第一部分:添加开放类应通过css
绑定发生:
data-bind="css: { 'classname' : state }"
在您的视图模型,添加一个cartIsOpen
观察到的和openCart
方法。
self.isOpen(true);
和淘汰赛:
data-bind="css: {'open': isOpen }"
jQuery的线可以被替换为:现在
self.isOpen = ko.observable(false);
,您可以通过添加这个数据绑定到其容器元素在视觉上打开你的车会照顾css。
现在,对于(更复杂)第二部分:
听在容器外的事件是不是淘汰赛的常规click
或event
结合能做到。所以你必须写一个自定义绑定。
听事件外某个元素可能相当棘手;我建议寻找堆栈溢出的一些一般建议。你需要非常小心event.stopPropagation()
它的工作。
在下面的例子中,我编写了一个clickOutside
绑定的粗略示例。请注意,这不是一个“完成”的例子:
- 任何点击您的页面将触发
closeOnClickOutside
方法;你需要找到一种方法来附加侦听器时isOpen
设置为true
,并处置一次它被设置为false
。
- 无论何时您想打开菜单,您都需要明确地停止点击事件到达文档。 (在示例中为
cancelBubble
)。否则,菜单立即打开和关闭。
var elementContainsChild = function(parent, child) {
// http://stackoverflow.com/a/2234986/3297291
var node = child.parentNode;
while (node !== null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
};
ko.bindingHandlers.clickOutside = {
init: function(element, valueAccessor) {
var cb = valueAccessor();
var closeOnClickOutside = function(e) {
if (e.target !== element &&
!elementContainsChild(element, e.target)) {
cb();
}
};
document.addEventListener("click", closeOnClickOutside);
}
}
var vm = {
isOpen: ko.observable(false)
};
ko.applyBindings(vm);
html, body { height: 100%; background: grey; }
.menu { background: yellow; display: none; }
.menu.open { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<button data-bind="click: isOpen.bind(null, true), clickBubble: false">open menu</button>
<div class="menu" data-bind="css: {'open' : isOpen }, clickOutside: isOpen.bind(null, false)">
<ul>
<li>Menu item</li>
<li>Menu item</li>
<li>Menu item</li>
<li>Menu item</li>
</ul>
</div>
我意识到,哇。我开始讨论这种错误。我会尝试你所说的。非常有帮助 – erics15
还有一个问题 - 我将如何链接到已经看起来像这样的按钮。 ?谢谢! – erics15
如果'addProductToCart'应该打开菜单('self.isOpen(true)'),则还需要将'clickBubble:false'数据绑定添加到按钮。如果你不这样做,按钮上的点击事件将(1)打开菜单,(2)一直向上冒泡,记录它(3)再次关闭菜单的位置(假设你还没有改变自定义绑定)。 – user3297291