入门

监控属性

使用内置绑定

控制文本和外观

绑定逻辑控制

处理表单属性

解析模板

高级应用

插件

更多信息

创建自定义绑定创建自定义绑定

你可以创建自己的自定义绑定 – 没有必要非要使用内嵌的绑定(像 clickvalue, 等)。你可以你封装复杂的逻辑或行为,自定义很容易使用和重用的绑定。

You’re not limited to using the built-in bindings like click, value, and so on — you can create your own ones. This is how to control how observables interact with DOM elements, and gives you a lot of flexibility to encapsulate sophisticated behaviors in an easy-to-reuse way.

例如,你可以在form表单里自定义像grid等这样的绑定。

重要:以下文档只应用在Knockout 1.1.1和更高版本,Knockout 1.1.0和以前的版本在注册API上是不同的。

Important: The following documentation applies to Knockout 1.1.1 and later. The API for registering bindings was different in Knockout 1.1.0 and earlier.

注册你的绑定注册你的绑定

添加子属性到 ko.bindingHandlers来注册你的绑定:

To register a binding, add it as a subproperty of ko.bindingHandlers:

  1. ko.bindingHandlers.yourBindingName = {
  2. init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
  3. // This will be called when the binding is first applied to an element
  4. // Set up any initial state, event handlers, etc. here
  5. },
  6. update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
  7. // This will be called once when the binding is first applied to an element,
  8. // and again whenever the associated observable changes value.
  9. // Update the DOM element based on the supplied values here.
  10. }
  11. };

… 然后就可以在任何DOM元素上使用了:

… and then you can use it on any number of DOM elements:

  1. <div data-bind="yourBindingName: someValue"> </div>

:你实际上没必要把:你实际上没必要把 init update 这两个callbacks都定义,你可以只定义其中的任意一个。

Note: you don’t actually have to provide both init and update callbacks — you can just provide one or the other if that’s all you need.

“update” 回调

当管理的observable改变的时候,KO会调用你的 update callback函数,然后传递以下参数:

Whenever the associated observable changes, KO will call your update callback, passing the following parameters:

  • element — 使用这个绑定的DOM元素
  • valueAccessor — JavaScript函数,通过 valueAccessor()) 可以得到应用到这个绑定的model上的当前属性值。
  • allBindingsAccessor — JavaScript函数,通过allBindingsAccessor ()得到这个元素上所有model的属性值。
  • viewModel — 传递给ko.applyBindings使用的 view model参数,如果是模板内部的话,那这个参数就是传递给该模板的数据。
  • element — The DOM element involved in this binding
  • valueAccessor — A JavaScript function that you can call to get the current model property that is involved in this binding. Call this without passing any parameters (i.e., call valueAccessor()) to get the current model property value.
  • allBindingsAccessor — A JavaScript function that you can call to get all the model properties bound to this DOM element. Like valueAccessor, call it without any parameters to get the current bound model properties.
  • viewModel — The view model object that was passed to ko.applyBindings. Inside a nested binding context, this parameter will be set to the current data item (e.g., inside a with: person binding, viewModel will be set to person).

例如,你可能想通过 例如,你可能想通过 visible 绑定来控制一个元素的可见性,但是你想让该元素在隐藏或者显示的时候加入动画效果。那你可以自定义自己的绑定来调用jQuery的 slideUp/slideDown 函数:

For example, you might have been controlling an element’s visibility using the visible binding, but now you want to go a step further and animate the transition. You want elements to slide into and out of existence according to the value of an observable. You can do this by writing a custom binding that calls jQuery’s slideUp/slideDown functions:

  1. ko.bindingHandlers.slideVisible = {
  2. update: function(element, valueAccessor, allBindingsAccessor) {
  3. // First get the latest data that we're bound to
  4. var value = valueAccessor(), allBindings = allBindingsAccessor();
  5. // Next, whether or not the supplied model property is observable, get its current value
  6. var valueUnwrapped = ko.utils.unwrapObservable(value);
  7. // Grab some more data from another binding property
  8. var duration = allBindings.slideDuration || 400; // 400ms is default duration unless otherwise specified
  9. // Now manipulate the DOM element
  10. if (valueUnwrapped == true)
  11. $(element).slideDown(duration); // Make the element visible
  12. else
  13. $(element).slideUp(duration); // Make the element invisible
  14. }
  15. };

然后你可以像这样使用你的绑定:

  1. <div data-bind="slideVisible: giftWrap, slideDuration:600">You have selected the option</div>
  2. <label><input type="checkbox" data-bind="checked: giftWrap" /> Gift wrap</label>
  3. <script type="text/javascript">
  4. var viewModel = {
  5. giftWrap: ko.observable(true)
  6. };
  7. ko.applyBindings(viewModel);
  8. </script>

当然,看来可能代码很多,但是一旦你创建了自定义绑定,你就可以在很多地方重用它。

Of course, this is a lot of code at first glance, but once you’ve created your custom bindings they can very easily be reused in many places.

“init” 回调

Knockout在DOM元素使用自定义绑定的时候会调用你的 init 函数。 init有两个重要的用途:

Knockout will call your init function once for each DOM element that you use the binding on. There are two main uses for init:

  • 为DOM元素设置初始值
  • 注册事件句柄,例如当用户点击或者编辑DOM元素的时候,你可以改变相关的observable值的状态。注册事件句柄,例如当用户点击或者编辑DOM元素的时候,你可以改变相关的observable值的状态。
  • To set any initial state for the DOM element
  • To register any event handlers so that, for example, when the user clicks on or modifies the DOM element, you can change the state of the associated observable

KO会传递和 update回调函数一样的参数。

KO will pass exactly the same set of parameters that it passes to the update callback.

继续上面的例子,你可以像让 slideVisible 在页面第一次显示的时候设置该元素的状态(但是不使用任何动画效果),而只是让动画在以后改变的时候再执行。你可以这样来做:

Continuing the previous example, you might want slideVisible to set the element to be instantly visible or invisible when the page first appears (without any animated slide), so that the animation only runs when the user changes the model state. You could do that as follows:

  1. ko.bindingHandlers.slideVisible = {
  2. init: function(element, valueAccessor) {
  3. var value = ko.utils.unwrapObservable(valueAccessor()); // Get the current value of the current property we're bound to
  4. $(element).toggle(value); // jQuery will hide/show the element depending on whether "value" or true or false
  5. },
  6. update: function(element, valueAccessor, allBindingsAccessor) {
  7. // Leave as before
  8. }
  9. };

这就是说 giftWrap p的初始值声明的是 false (例如 giftWrap: ko.observable(false)),然后让初始值会让关联的DIV隐藏,之后用户点击checkbox的时候会让元素显示出来。

This means that if giftWrap was defined with the initial state false (i.e., giftWrap: ko.observable(false)) then the associated DIV would initially be hidden, and then would slide into view when the user later checks the box.

DOM事件之后更新observable值

你已经值得了如何使用update回调,当observable值改变的时候,你可以更新相关的DOM元素。但是其它形式的事件怎么做呢?比如当用户对某个DOM元素有某些action操作的时候,你想更新相关的observable值。

You’ve already seen how to use update so that, when an observable changes, you can update an associated DOM element. But what about events in the other direction? When the user performs some action on a DOM element, you might want to updated an associated observable.

你可以使用 init 回调来注册一个事件句柄,这样可以改变相关的observable值,例如,

You can use the init callback as a place to register an event handler that will cause changes to the associated observable. For example,

  1. ko.bindingHandlers.hasFocus = {
  2. init: function(element, valueAccessor) {
  3. $(element).focus(function() {
  4. var value = valueAccessor();
  5. value(true);
  6. });
  7. $(element).blur(function() {
  8. var value = valueAccessor();
  9. value(false);
  10. });
  11. },
  12. update: function(element, valueAccessor) {
  13. var value = valueAccessor();
  14. if (ko.utils.unwrapObservable(value))
  15. element.focus();
  16. else
  17. element.blur();
  18. }
  19. };

现在你可以通过hasFocus绑定来读取或者写入这个observable值了:

Now you can both read and write the “focusedness” of an element by binding it to an observable:

  1. <p>Name: <input data-bind="hasFocus: editingName" /></p>
  2. <!-- Showing that we can both read and write the focus state -->
  3. <div data-bind="visible: editingName">You're editing the name</div>
  4. <button data-bind="enable: !editingName(), click:function() { editingName(true) }">Edit name</button>
  5. <script type="text/javascript">
  6. var viewModel = {
  7. editingName: ko.observable()
  8. };
  9. ko.applyBindings(viewModel);
  10. </script>

(c) knockoutjs.com