0

无论如何要添加“全局”自定义绑定吗?例如,我希望为每个绑定的元素触发一个绑定,而不必将绑定添加到data-bind属性。将其视为在数据绑定过程中某个时间触发的初始化程序。

我真正想做的是:当一个新模型被添加到一个新模型时observableArray,我想首先自动关注新模型input,以便用户可以立即开始输入。我认为这不适用于任何现有的绑定。

ko.bindingHandlers.attach = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        valueAccessor().boundElements.push(element);
    }
};

那行得通,但我宁愿不必data-bind="attach: $data"对每个绑定元素都做。有没有办法告诉 KOattach在元素上有另一个绑定时始终使用该绑定。

注意:写完这篇文章后,我想我还是决定使用手动方法,但我仍然想知道这是否可能。

4

2 回答 2

2

这个答案特别是关于如何在input添加新模型时首先关注视图,因为我提出的这样做的技术与你的完全不同。

我在最近的一个项目中也有同样的要求,基本上通过在我的视图模型中包含一个名为firstHasFocus. 每当该视图模型变为活动状态时,例如切换“选项卡”时,我都会设置firstHasFocustrue. 在视图中,第一个input绑定到使用hasfocus.

这是我的代码中的一个示例,它响应向导类型界面中的“下一步”按钮。它切换到下一步,如果这是当前可用的最后一步,它会关注第一个输入。

this.goNext = function() {
    if (this.isNextAvailable()) {
        var newIndex = this.currentStepIndex() + 1;
        this.setCurrentStep(this.steps()[newIndex], newIndex);
        if (!this.isNextAvailable()) {
            this.currentStep().firstHasFocus(true);
        }
    }
};

为了确保firstHasFocus(true)始终更新绑定,它被定义为始终通知:

this.firstHasFocus = ko.observable(false).extend({notify: 'always'});

每个步骤都有一个对应的视图,该视图可以包含对firstHasFocus.

<h1>Select the Station Info Columns</h1>
<form>
    <label for="stationColumn">Station Name</label>
    <select id="stationColumn" name="stationColumn" data-bind="
                    options: data.headerVarNames, optionsCaption: '----',
                    value: data.stationHeaderName, valueUpdate: 'afterkeydown',
                    setfocus: firstHasFocus"></select>
    <label for="siteColumn">Site Name</label>
    <select id="siteColumn" name="siteColumn" data-bind="
                    options: data.headerVarNames, optionsCaption: '----',
                    value: data.siteNameHeaderName"></select>
...

我使用自定义绑定,setfocus而不是标准hasfocus,因为不想blur被调用。这是我的setfocus绑定:

ko.bindingHandlers.setfocus = {
    init: function(element, valueAccessor) {
        var modelValue = valueAccessor();
        if (!ko.isWriteableObservable(modelValue)) {
            throw new Error('setfocus must be used with a writable observable');
        }
        var writeValue = function(event) {
            var modelValue = valueAccessor(),
                valueToWrite = element.ownerDocument.activeElement === element;
            if (event.type == 'focusin' && !valueToWrite)
                element.focus();
            else if (valueToWrite != modelValue())
                modelValue(valueToWrite);
        };
        ko.utils.registerEventHandler(element, "focus", writeValue);
        ko.utils.registerEventHandler(element, "focusin", writeValue); // For IE
        ko.utils.registerEventHandler(element, "blur",  writeValue);
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor()();   // access and unwrap observable
        setTimeout(function() {
            if (value && element.offsetWidth && element.offsetHeight && document.activeElement && document.activeElement != element) {
                element.focus();
                ko.utils.triggerEvent(element, "focusin"); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
            }
        });
    }
};
于 2013-04-25T23:41:46.317 回答
0

通常,您的视图模型不需要访问 DOM 元素(这就是绑定的用途)。但是有一种方法可以做到这一点,它被称为自定义绑定提供程序。这没有正式记录,但描述是Ryan Niemeyer 的博客上的一些细节。

因此,这是您可以修改绑定提供程序以添加此行为的一种方法:

var origNodeHasBindings = ko.bindingProvider.instance.nodeHasBindings,
    origGetBindings = ko.bindingProvider.instance.getBindings;

ko.bindingProvider.instance.nodeHasBindings = function(node) {
    return (node.nodeType === 1) || origNodeHasBindings(node);
};
ko.bindingProvider.instance.getBindings = function(node, bindingContext) {
    var bindings = origGetBindings.call(this, node, bindingContext) || {};
    bindings.attach = bindingContext.$data;
    return bindings;
};
于 2013-04-25T02:10:30.447 回答