如何在鼠标悬停时使用 Knockout.js 更改 CSS class?

How to use Knockout.js to change a CSS class on mouseover?

我有一个由 Knockout.js foreach 数据绑定填充的图像网格。默认情况下,网格中的每个图像都有一个由背景颜色设置的黑色轮廓。当用户将鼠标悬停在每个图像上时,我希望该轮廓变为白色以表示它已突出显示。

目前,我正在使用两个事件处理程序,一个用于 mouseenter,一个用于 mouseleave
第一个更改图像的 CSS class一个有白色背景的。后者将其改回黑色。但是,当鼠标进入图像时,两者都会被调用(通过调试确认),因此看不到任何变化。

HTML如下: (注:每张图片都有一个fileName属性表示图片文件的位置。有两个CSS classes叫做blackwhite,一个是每个突出显示状态。)

<div id="palette-container" data-bind="foreach: images" style="display: inline-block">
    <div style="float: left">
        <img class="black" data-bind="attr: { id: fileName, src: $parent.imagePath(fileName) }, 
                                      event: { mouseenter: $parent.toWhite(fileName), mouseleave: $parent.toBlack(fileName) }, 
                                      style: { width: $parent.size, height: $parent.size }">
    </div>
</div>

如您所见,我现在并没有以非常优雅的方式执行此操作。我将每个元素的 id 绑定到其唯一的 fileName 属性。然后我将文件名传递给事件处理程序,以便可以通过 id 访问元素以更改 CSS class。

(A)为什么鼠标进入图像时mouseentermouseleave都被调用?

(B) 实现所需突出显示功能的更简单方法是什么?

为什么不保持简单。使用 css :hover

//add a hover effect to class .black
.black{ 
border: solid 5px black
} .black:hover { 
border: solid 5px green;
} 

jsfiddle: http://jsfiddle.net/nmx2og9g/1/

Knockout 的目的是通过绑定处理程序[=34]以声明方式将视图(您的 HTML)连接(绑定)到您的视图模型(JavaScript 对象) =].但是,并非每个可能的 DOM-to-viewmodel 交互都有预定义的绑定处理程序。

在您的特定情况下(更改样式),您可以简单地使用 :hover CSS 伪 class。您的视图会响应鼠标移动,但您的视图模型不会注意到任何这些。

如果您想更改不同的 DOM 属性 以响应鼠标移动,例如元素的文本,CSS 将不再起作用。您可以使用 knockout 的 event 绑定 "manually" - 或者您可以创建一个自定义绑定处理程序来设置视图模型的属性之一以响应 mouseentermouseleave 事件。

自定义绑定处理程序的优势在于,您现在拥有一个实际的可观察对象,您可以将其作为其他行为的基础,并且您在视图中输入的内容更少,这在您多次使用它时非常有用.

以下更改元素的文本和 CSS class 悬停:

ko.bindingHandlers.hover = {
    init: function (element, valueAccessor) {
        var value = valueAccessor();
        ko.applyBindingsToNode(element, {
            event: {
                mouseenter: function () { value(true) },
                mouseleave: function () { value(false) }
            }
        });
    }
}

function Item() {
  this.isHovering = ko.observable(false);
}

ko.applyBindings({
  items: [
    new Item(),
    new Item(),
    new Item(),
    new Item(),
    new Item()
  ]
});
div.item {
  float: left;
  width: 50px;
  height: 50px;
  line-height: 50px;
  text-align: center;
  border: 1px solid black;
  margin: 0 5px 5px 0;
}
div.item.active {
  border-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div data-bind="foreach: items">
  <div class="item" data-bind="
    hover: isHovering, text: isHovering, css: {active: isHovering}
  ">
  </div>
</div>