event绑定

目的

event绑定在DOM元素上添加指定的事件句柄以便元素被触发的时候执行定义的JavaScript 函数。大部分情况下是用在keypress,mouseover和mouseout上。

例子

<div>
    <div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }">
        Mouse over me
    </div>
    <div data-bind="visible: detailsEnabled">
        Details
    </div>
</div>
<script type="text/javascript">
    var viewModel = {
        detailsEnabled: ko.observable(false),
        enableDetails: function() {
            this.detailsEnabled(true);
        },
        disableDetails: function() {
            this.detailsEnabled(false);
        }
    };
</script>

每次鼠标在第一个元素上移入移出的时候都会调用view model上的方法来toggle detailsEnabled的值,而第二个元素会根据detailsEnabled的值自动显示或者隐藏。

参数

主参数

你需要传入的是一个JavaScript对象,他的属性名是事件名称,值是你所需要执行的函数。

你可以声明任何JavaScript函数 – 不一定非要是view model里的函数。你可以声明任意对象上的任何函数,例如:event: { mouseover: someObject.someFunction }。

View model上的函数在用的时候有一点点特殊,就是不需要引用对象的,直接引用函数本身就行了,比如直接写event: { mouseover: enableDetails }就可以了,而无需写成:event: { mouseover: viewModel.enableDetails }(尽管是合法的)。

其它参数

注1:传参数给你的click 句柄

最简单的办法是传一个function包装的匿名函数:

<button data-bind="event: { mouseover: function() { viewModel.myFunction('param1', 'param2') } }">
    Click me
</button>

这样,KO就会调用这个匿名函数,里面会执行viewModel.myFunction(),并且传进了'param1' 和'param2'参数。

注2:访问事件源对象

有些情况,你可能需要使用事件源对象,Knockout会将这个对象传递到你函数的第一个参数:

<div data-bind="event: { mouseover: myFunction }">
    Mouse over me
</div>
<script type="text/javascript">
    var viewModel = {
        myFunction: function(event) {
            if (event.shiftKey) { //do something different when user has shift key down             } else {                 //do normal action             }         }     };
                
</script>

如果你需要的话,可以使用匿名函数的第一个参数传进去,然后在里面调用:

<div data-bind="event: { mouseover: function(event) { viewModel.myFunction(event, 'param1', 'param2') } }">
    Mouse over me
</div>

这样,KO就会将事件源对象传递给你的函数并且使用了。

注3: 允许执行默认事件

默认情况下,Knockout会阻止冒泡,防止默认的事件继续执行。例如,如果在一个input标签上绑定一个keypress事件,当你输入内容的时候,浏览器只会调用你的函数而不是天价你输入的值。另外一个例子click绑定,当你点击一个a连接,在执行完自定义事件时它不会连接到href地址。因为你的自定义事件主要就是操作你的view model,而不是连接到另外一个页面。

当然,如果你想让默认的事件继续执行,你可以在你event的自定义函数里返回true。

注4:控制this句柄

初学者可以忽略这小节,因为大部分都用不着,高级用户可以参考如下内容:

KO在调用你定义的event绑定函数时,会将view model传给this对象(也就是ko.applyBindings使用的view model)。主要是方便你在调用你在view model里定义的方法的时候可以很容易再调用view model里定义的其它属性。例如:this.someOtherViewModelProperty。

如果你想引用其它对象,我们有两种方式:

  • 你可以和注1里那样使用匿名函数,因为它支持任意JavaScript 对象。

  • 你也可以直接引用任何函数对象。你可以使用bind使callback函数设置this为任何你选择的对象。例如:

<div data-bind="event: { mouseover: someObject.someFunction.bind(someObject) }">
    Mouse over me
</div>

如果你是C#或Java开发人员,你可以疑惑为什么我们还要用bind函数到一个对象想,特别是像调用someObject.someFunction。 原因是在JavaScript里,函数自己不是类的一部分,他们在单独存在的对象,有可能多个对象都引用同样的someFunction函数,所以当这个函数被调用的时候它不知道谁调用的(设置this给谁)。在你bind之前运行时是不会知道的。KO默认情况下设置this对象是view model,但你可以用bind语法重定义它。

在注1里使用匿名函数的时候没有具体的要求,因为JavaScript代码 someObject.someFunction()就意味着调用someFunction,然后设置this到 someObject对象上。

注5:防止事件冒泡

默认情况下,Knockout允许event事件继续在更高一层的事件句柄上冒泡执行。例如,如果你的元素和父元素都绑定了mouseover事件,那么如果你的鼠标在该元素移动的时候两个事件都会触发的。如果需要,你可以通过额外的绑定youreventBubble来禁止冒泡。例如:

<div data-bind="event: { mouseover: myDivHandler }">
    <button data-bind="event: { mouseover: myButtonHandler }, mouseoverBubble: false">
        Click me
    </button>
</div>

默认情况下,myButtonHandler会先执行,然后会冒泡执行myDivHandler。但一旦你设置了mouseoverBubble为false的时候,冒泡事件会被禁止。

依赖性

除KO核心类库外,无依赖。

我们也可以使用event binding来进行事件绑定,比如:keypress, mouseover 、 mouseout等

(1)、使用mouseover和mouseout控制是否显示div

<script type="text/javascript" src="knockout-2.2.0.js">
</script>
<div>
    <div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }">
        Mouse over me
    </div>
    <div data-bind="visible: detailsEnabled">
        Details
    </div>
</div>
<script type="text/javascript">
    var viewModel = {
        detailsEnabled: ko.observable(false),
        enableDetails: function() {
            this.detailsEnabled(true);
        },
        disableDetails: function() {
            this.detailsEnabled(false);
        }
    };
    ko.applyBindings(viewModel);
</script>

(2)、参数传递

当使用event binding的时候,Knockoutjs会默认将当前的Model Value作为第一个参数传递给事件方法。如下:

<script type="text/javascript" src="knockout-2.2.0.js">
</script>
<ul data-bind="foreach: places">
    <li data-bind="text: $data, event: { mouseover: $parent.logMouseOver }">
    </li>
</ul>
<p>
    You seem to be interested in:
    <span data-bind="text: lastInterest">
    </span>
</p>
<script type="text/javascript">
    function MyViewModel() {
        var self = this;
        self.lastInterest = ko.observable();
        self.places = ko.observableArray(['London', 'Paris', 'Tokyo']);

        // The current item will be passed as the first parameter, so we know which place was hovered over 
        self.logMouseOver = function(place) {
            self.lastInterest(place);
        }
    }
    ko.applyBindings(new MyViewModel());
</script>

(3)、传递多个参数

在进行多个参数传递时,我们可以参照click binding中的多个参数传递,如下:

<div data-bind="event: { mouseover: function(data, event) { myFunction('param1', 'param2', data, event) } }">
    Mouse over me
</div>

我们也可以使用下面的方法进行多个参数的传递:

<button data-bind="event: { mouseover: myFunction.bind($data, 'param1', 'param2') }">
    Click me
</button>

(4)、同样的在event binding中也会有事件的冲突,在click binding中我们使用clickBubble来处理,如果我们要mouseover事件的话我们可以使用mouseoverBubble来处理,如果使用mouseout的话我们可以使用mouseoutBubble来处理等等。