为什么我的KnockoutJS自定义绑定会被触发?

时间:2011-11-30 10:27:36

标签: javascript data-binding binding mvvm knockout.js

我有一个奇怪的情况。基本上,我有两个自定义绑定,用于将DOM元素设置为它的新值。这些是aWidth和aRight,分别为宽度值和右值设置动画。

我已经实现了这样的绑定:

<div class='classname' data-bind="aRight: right, aWidth: containerWidth, style: { zIndex: zindex, left: (left() + 'px'), height: (containerHeight() + 'px') }">

...并且自定义绑定看起来像这样:

            ko.bindingHandlers.aWidth =
            {
                update: function (element, valueAccessor, allBindingsAccessor, context)
                {
                    // Get the value accessor
                    var value = valueAccessor();

                    // Get the new width and the duration of the animation
                    var newWidth = ko.utils.unwrapObservable(value);
                    var duration = 500;

                    $(element).animate({ width: newWidth }, duration, "swing");
                }
            };

            ko.bindingHandlers.aRight =
            {
                update: function (element, valueAccessor, allBindingsAccessor, context)
                {
                    // Get the value accessor
                    var value = valueAccessor();

                    // Get the new width and the duration of the animation
                    var newRight = ko.utils.unwrapObservable(value);
                    var duration = 500;

                    $(element).animate({ right: newRight }, duration, "swing");

                    console.log("aRight Called: newRight - " + newRight + ", duration - " + duration);
                }
            };

因此,当我们更改除两个自定义绑定observable之外的observable时,问题就出现了,例如zindex。

如果我们更改了可观察的zindex,则值会在DOM中正确更新,但由于某种原因,我的aRight绑定也会被触发!...

我的aRight自定义绑定中没有任何引用,所以肯定不能依赖它?

当我的aWidth绑定也被触发时,我的aRight绑定也会被触发,这也有点奇怪!

有没有人对此有任何想法?

非常感谢!

安迪。

更新

这是更新索引的视图模型的一部分,当导致我的aRight自定义绑定触发时(顺便说一下这是非常多的psudo代码!):

    var page = function()
    {
        this.zindex = ko.observable(0);
        this.right = ko.observable(0);
        // and other observables....
    }

    var viewModel = function()
    {
        var pages = ko.oberservableArray();
        // populate the pages array etc...

        this.someMethod = function()
        {
            // Do some stuff...
            this.anotherMethod();
            // Do some other stuff
        }
        .bind(this);

        this.anotherMethod() = function
        {
            var pageCount = this.pages().length;
            for (var pageNum = 0; pageNum < pageCount; pageNum++)
            {
                var page = this.pages()[pageNum];
                page.zindex(/* a different value */); // This is what causes my aRight binding to fire...
            }
        }
        .bind(this);
    }

更新

我刚看了一篇帖子:http://groups.google.com/group/knockoutjs/browse_thread/thread/26a3157ae68c7aa5/44c96d1b748f63bb?lnk=gst&q=custom+binding+firing#44c96d1b748f63bb

话说:

  

此外,绑定将使其更新功能再次运行,如果   同样触发了同一数据绑定属性中的另一个绑定。

这是否意味着我所看到的是,当触发data-bind属性中的任何其他绑定时,我的自定义绑定被触发(这恰好可能是zindex是我看到的第一个更改)?这不是有点奇怪/错误吗?...

更新

我有一个简单的小提琴,我认为这几乎总结了我的问题。似乎对同一个数据绑定属性的任何绑定都会导致它更新!

http://jsfiddle.net/J6EPx/2/

嗯......我想要通过手动检查我的自定义绑定来确定值是否实际发生了变化!这不会破坏绑定的实际点吗?

我还在Knockout论坛上发布了一个更精确的问题:http://groups.google.com/group/knockoutjs/browse_thread/thread/d2290d96e33f1d5a

1 个答案:

答案 0 :(得分:9)

这是目前的设计。触发任何绑定时,将触发数据绑定中的所有绑定。这是因为它们都包含在一个dependentObservable中。在某些情况下,绑定之间存在依赖关系(如果更新选项,则需要运行值以确保它仍然是有效值)。但是,在某些情况下,这确实会导致问题。

在创建有助于缓解此行为的自定义绑定时,可以使用不同的模式。您可以在“init”函数中创建自己的dependentObservable,而不是在“update”函数中定义功能的内容。它看起来像是:

ko.bindingHandlers.custBinding= {
    init: function(element, valueAccessor) {
        ko.dependentObservable({
            read: function() {
                ko.utils.unwrapObservable(valueAccessor());
                alert("custBinding triggered"); 
            },
            disposeWhenNodeIsRemoved: element
        });
    }
};

http://jsfiddle.net/rniemeyer/uKUfy/