KnockoutJS 3.1.0:" with"绑定和过渡

时间:2014-07-26 01:01:23

标签: javascript knockout.js

在我的一个项目中,我一直在使用KnockoutJS 2.2.1。我一直在使用自定义指令通过滑动动画对象变化,如下所示:

ko.bindingHandlers.withSliding = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        return ko.bindingHandlers.with.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    },

    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        slideOut(function () {
            ko.bindingHandlers.with.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);

            slideIn();
        });
    }
};

现在我想更新到Knockout 3.1.0。但问题是:“with”绑定现在缺少“ko.bindingHandlers.with”的“update”子属性。因此,无法推迟模板更新。

任何解决方案?

提前谢谢。

2 个答案:

答案 0 :(得分:1)

我可以想到几个选项:

  • 如果你不关心过渡(你似乎要滑出来,所以你可能会照顾),那么你可以在里面的第一个元素上放一个简单的slideIn绑定具有with绑定的容器。在绑定的init函数中,您可以隐藏元素,然后将其滑入。

  • 否则,您可以选择包装template绑定而不是with绑定。如果将选项对象传递给template绑定并排除name属性,则它将使用子元素作为其匿名模板。

update函数中,您还需要确保同步访问任何可观察的依赖项(不仅仅是在异步回调中),以便它再次触发。

可能是这样的:

ko.bindingHandlers.templateSliding = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        return ko.bindingHandlers.template.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    },

    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var data, options = ko.unwrap(valueAccessor());

        if (options && options.data) {
            //make sure that we have a dependency on the template's data
            data = ko.unwrap(options.data);   
        }

        $(element).slideUp("fast", function () {
            ko.bindingHandlers.template.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);

            if (data) {
                $(element).slideDown();
            }
        });            
    }
};

示例:http://jsfiddle.net/rniemeyer/G3dn4/

答案 1 :(得分:1)

通常,Knockout不支持直接调用绑定处理程序的initupdate函数。在Knockout 3.1中,with绑定在其init函数中进行了所有更新,因此无论如何都无法拦截它。

Knockout确实提供了一种绑定标准方式来拦截添加或删除的内容 - foreach绑定。从Knockout 3.0开始,还有一种方法可以使用preprocess function来包装其他绑定。将这两者放在一起,这就是withSliding绑定的样子:

ko.bindingHandlers.withSliding = {
    preprocess: function (value, name, addBinding) {
        addBinding('foreach', 
            '{'+
                'data:[ko.unwrap('+ value +')],'+
                'beforeRemove:function(elem) { if (elem.nodeType === 1) $(elem).slideUp(function() { $(elem).remove(); })},'+
                'afterAdd:function(elem) { if (elem.nodeType === 1) $(elem).hide().slideDown()}'+
            '}'
        );
    }
};

jsFiddle:http://jsfiddle.net/mbest/wRbzL/(使用RP Niemeyer的模板)

或者,您的自定义绑定可以执行所有操作(不包装任何其他绑定)。

ko.bindingHandlers.withSliding = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var $element = $(element),
            template = $element.children().clone();
        $element.hide();

        ko.computed(function() {
            var dataValue = ko.unwrap(valueAccessor());
            $element.slideUp(function () {
                $element.empty();
                if (dataValue) {
                    $element.append(template.clone()).hide();
                    ko.applyBindingsToDescendants(bindingContext.createChildContext(dataValue), element);
                    $element.slideDown();
                }
            });
        }, null, { disposeWhenNodeIsRemoved: element });

        return { controlsDescendantBindings: true };
    }
};

jsFiddle:http://jsfiddle.net/mbest/pzsCX/