【问题标题】:Why is my KnockoutJS custom binding being triggered?为什么会触发我的 KnockoutJS 自定义绑定?
【发布时间】:2012-01-09 14:25:23
【问题描述】:

我遇到了一个奇怪的情况。基本上,我有两个自定义绑定,用于将 DOM 元素设置为新值。它们是 aWidth 和 aRight,它们分别为 width 和 right 值设置动画。

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

<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。

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

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

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

有人对此有任何想法吗?

非常感谢!

安迪。

更新

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

    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

说:

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

这是否意味着我看到的是当任何其他绑定 in data-bind 属性被触发时我的自定义绑定被触发(它只是碰巧可能 zindex 是我看到的第一个变化)?这不是有点奇怪/错误吗?...

更新

我有一个简单的小提琴,我认为它可以很好地总结我的问题。似乎对同一 data-bind 属性的任何绑定都将导致它更新!

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

嗯......我想我必须通过手动检查我的自定义绑定来解决这个问题,以确定该值是否实际发生了变化!这不会破坏绑定的实际点吗???

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

【问题讨论】:

  • 不知道是不是和$(element).animate()有关?如果您不直接更改宽度/高度而不是动画,会发生什么?
  • 好问题...等一下... :)
  • @Alex Key,不,使用 $(element).css("right", newRight + "px");至少没有帮助。索引更新时仍然触发!不过感谢您的建议!
  • 引人入胜,这很奇怪!这个问题得到了我的一颗星:-) 我很想看看你的解决方案是什么,祝你好运。我自己在玩淘汰赛,所以如果我弄清楚了,我会给你留言。
  • 谢谢,我会不断更新这篇文章! :)

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


【解决方案1】:

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

创建自定义绑定时可以使用不同的模式来帮助缓解这种行为。您实际上将在“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/

【讨论】:

  • 我花了一点时间才明白这一点,但你的建议听起来很明智!不过我必须承认,我有点惊讶默认是将它们全部包装在一个dependentObservable 中。我不认为 WPF / Silverlight 以这种方式工作......并不是说它是错误的......只是令人困惑! :)
  • 默认行为在许多情况下并不理想,可以/应该改进。我们只需要在打破现有行为之间取得平衡(有些人目前使用不访问可观察对象并依赖于触发其他绑定的自定义绑定)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-02
  • 2015-07-27
  • 2018-12-24
相关资源
最近更新 更多