KnockoutJS 3.X API 第五章 高级应用(2) 控制后代绑定

注意:这是一种高级技术,通常仅在创建可重用绑定的库时使用。

默认情况下,绑定仅影响它们应用到的元素。 但是如果你想影响所有的后代元素呢?

为此,只需从绑定的init函数中返回{controlsDescendantBindings:true}即可。

示例1:控制是否应用后代绑定

对于一个非常简单的例子,这里有一个名为allowBindings的自定义绑定,允许后代绑定仅当它的值为true时才应用。 如果值为false,则allowBindings告诉Knockout它负责后代绑定,因此它们不会像往常一样绑定。

ko.bindingHandlers.allowBindings = {
    init: function(elem, valueAccessor) {
        // Let bindings proceed as normal *only if* my value is false
        var shouldAllowBindings = ko.unwrap(valueAccessor());
        return { controlsDescendantBindings: !shouldAllowBindings };
    }
};

要使此效果生效,以下是一个示例用法:

<div data-bind="allowBindings: true">
    <!-- This will display Replacement, because bindings are applied -->
    <div data-bind="text: 'Replacement'">Original</div>
</div>
 
<div data-bind="allowBindings: false">
    <!-- This will display Original, because bindings are not applied -->
    <div data-bind="text: 'Replacement'">Original</div>
</div>

示例2:为子孙绑定提供附加值

通常,使用controlsDescendantBindings的绑定也将调用ko.applyBindingsToDescendants(someBindingContext,element)来对一些修改的绑定上下文应用后代绑定。 例如,您可以使用一个名为withProperties的绑定将一些额外的属性附加到绑定上下文,然后可用于所有后代绑定:

ko.bindingHandlers.withProperties = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Make a modified binding context, with a extra properties, and apply it to descendant elements
        var innerBindingContext = bindingContext.extend(valueAccessor);
        ko.applyBindingsToDescendants(innerBindingContext, element);
 
        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    }
};

正如你可以看到,绑定上下文有一个扩展函数,产生一个带有额外属性的克隆。 extend函数接受具有要复制的属性的对象或返回此类对象的函数。 函数语法是首选的,以便将来在绑定值中的更改始终在绑定上下文中更新。 此过程不会影响原始绑定上下文,因此不会影响同级元素的危险 - 它只会影响后代。

以下是使用上述自定义绑定的示例:

<div data-bind="withProperties: { emotion: 'happy' }">
    Today I feel <span data-bind="text: emotion"></span>. <!-- Displays: happy -->
</div>
<div data-bind="withProperties: { emotion: 'whimsical' }">
    Today I feel <span data-bind="text: emotion"></span>. <!-- Displays: whimsical -->
</div>

示例3:在绑定上下文层次结构中添加额外的级别

绑定(如with和foreach)在绑定上下文层次结构中创建额外的级别。 这意味着它们的后代可以通过使用$ parent,$ parents,$ root或$ parentContext来访问外部级别的数据。

如果你想在自定义绑定中这样做,那么不使用bindingContext.extend(),使用bindingContext.createChildContext(someData)。 这返回一个新的绑定上下文,其viewmodel是someData,其$ parentContext是bindingContext。 如果需要,您可以使用ko.utils.extend扩展具有额外属性的子上下文。 例如,

ko.bindingHandlers.withProperties = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // Make a modified binding context, with a extra properties, and apply it to descendant elements
        var childBindingContext = bindingContext.createChildContext(
            bindingContext.$rawData, 
            null, // Optionally, pass a string here as an alias for the data item in descendant contexts
            function(context) {
                ko.utils.extend(context, valueAccessor());
            });
        ko.applyBindingsToDescendants(childBindingContext, element);
 
        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    }
};

这个更新的withProperties绑定现在可以以嵌套方式使用,每个嵌套级别都可以通过$ parentContext访问父级别:

<div data-bind="withProperties: { displayMode: 'twoColumn' }">
    The outer display mode is <span data-bind="text: displayMode"></span>.
    <div data-bind="withProperties: { displayMode: 'doubleWidth' }">
        The inner display mode is <span data-bind="text: displayMode"></span>, but I haven't forgotten
        that the outer display mode is <span data-bind="text: $parentContext.displayMode"></span>.
    </div>
</div>

通过修改绑定上下文和控制后代绑定,一个强大的和高级的工具来创建自己的自定义绑定机制。

原文地址:https://www.cnblogs.com/smallprogram/p/5968616.html