【问题标题】:jQueryUI Spinner widget with knockout带有淘汰赛的 jQueryUI Spinner 小部件
【发布时间】:2012-10-07 10:39:53
【问题描述】:

如何在 Knockout 绑定输入中使用 jQuery UI Spinner 小部件?

    <tbody data-bind="foreach: orders">
        <tr>
            <td data-bind="text: Name"></td>
            <td><input type="number" style="width: 100px;" data-bind="value: Price" /></td>
            <td><input type="number" style="width: 50px;" data-bind="value: VAT" /></td>
            <td><input type="number" style="width: 50px;" data-bind="value: Number" /></td>
            <td data-bind="text: Final()"></td>
            <td><a href="javascript:void(0);" data-bind="click: $root.removeOrder">Remove</a></td>
        </tr>    
    </tbody>

【问题讨论】:

  • 您要将微调器应用到哪个字段?

标签: jquery jquery-ui knockout.js


【解决方案1】:

最好的方法是创建custom binding 以将spinner 绑定到输入:

ko.bindingHandlers.spinner = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        //initialize spinner with some optional options
        var options = allBindingsAccessor().spinnerOptions || {};
        $(element).spinner(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "spinchange", function () {
            var observable = valueAccessor();
            observable($(element).spinner("value"));
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).spinner("destroy");
        });

    },
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            current = $(element).spinner("value");

        if (value !== current) {
            $(element).spinner("value", value);
        }
    }
};

然后就用它代替value绑定:

<input
    type="number"
    style="width: 100px;"
    data-bind="spinner: Price, spinnerOptions: { min: 0 } " />

这是工作小提琴:http://jsfiddle.net/vyshniakov/SwKGb/

【讨论】:

  • @Artem - 很棒的代码!有什么方法可以让它在每次点击时触发?不只是在焦点离开时?
  • @Artem - 找到“部分”它 - 将“spinchange”更改为“spinstop” - 只是在 Chrome 中不起作用
  • 我改进了小提琴,以便您可以使用诸如 Modernizr 之类的功能检测库仅在不支持本机微调器时启用 jQuery UI 微调器:jsfiddle.net/mberkom/pCJWc
  • @Artem - 干得好。一流的复制粘贴目标。 :D
【解决方案2】:

@Artem Vyshniakov 的回答是正确的。但是,如果您正在寻找 IE polyfill 而不是在支持它的浏览器中替换 html5 数字输入,请尝试以下操作:

    ko.bindingHandlers.spinner = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        if (Modernizr.inputtypes.number) {
            ko.bindingHandlers.value.init.apply(null, arguments);
        } else {
            //initialize spinner with some optional options
            var options = allBindingsAccessor().spinnerOptions || {};
            $(element).spinner(options);

            //handle the field changing
            $(element).on("spinstop", function () {
                var observable = valueAccessor();
                observable($(element).spinner("value"));
            });

            //handle disposal
            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $(element).off("spinstop");
                $(element).spinner("destroy");
            });
        }

    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        if (Modernizr.inputtypes.number) {
            ko.bindingHandlers.value.update.apply(null, arguments);
        } else {
            var value = ko.utils.unwrapObservable(valueAccessor());

            var disable = allBindingsAccessor().disable;

            if (typeof disable !== "undefined") {
                $(element).spinner((disable) ? "disable" : "enable");
            }

            var current = $(element).spinner("value");
            if (value !== current) {
                $(element).spinner("value", value);
            }
        }
    }
};

function Order(name, price, vat, number) {
    var self = this;

    self.Name = ko.observable(name);
    self.Price = ko.observable(price);
    self.VAT = ko.observable(vat);
    self.Number = ko.observable(number);

    self.Final = ko.computed(function() {
        return (self.Price() + self.VAT()) * self.Number();
    });
}

function ViewModel() {
    var self = this;

    self.orders = ko.observableArray();

    self.removeOrder = function(item) {
        self.orders.remove(item);
    };

    self.save = function() {
        alert(ko.toJSON(self));
    };
}

var viewModel = new ViewModel();
viewModel.orders.push(new Order("Sugar", 100, 15, 3));
viewModel.orders.push(new Order("Salt", 200, 25, 4));
viewModel.orders.push(new Order("Milk", 200, 35, 1));

ko.applyBindings(viewModel);

在这里完成小提琴:http://jsfiddle.net/mberkom/pCJWc/

【讨论】:

    【解决方案3】:

    此页面上的答案是正确且有用的。但是,我发现当有人在字段中输入值时,我的行为变得很糟糕。每次按键似乎也会触发“spinstop”事件。此外,按键绕过了字段格式和options.step。幸运的是,我们可以检查传入的事件以了解实际发生的情况。可能有更好的方法,但我想我还是会分享。

    // Abstract to a function to allow for multiple binding types
    function createSpinner(defaultOptions) {
        return {
            init: function (element, valueAccessor, allBindingsAccessor) {
                var options = $.extend(true, {}, allBindingsAccessor().spinnerOptions, defaultOptions);
                var widget = $(element);
                var observable = valueAccessor();
    
                widget.spinner(options);
    
                // handle field changes onblur [copies field -> model]
                ko.utils.registerEventHandler(element, "blur", function (event) {
                    var inputValue = Number(widget.spinner("value"));
                    var modelValue = observable();
                    if (inputValue !== modelValue) {
                        // Set the widget (this forces formatting and rounding) - does not fire events
                        widget.spinner("value", inputValue);
                        // Read the value back out (saves us rounding)
                        var numberValue = Number(widget.spinner("value"));
                        // Set the observable
                        observable(numberValue);
                    }
                });
    
                // handle other field changes
                ko.utils.registerEventHandler(element, "spinstop", function (event) {
                    // jQuery.spinner spinstop is a bit overzealous with its spinstop event.
                    if (event.keyCode !== undefined) {
                        // If it has a keyCode someone is typing... so don't interfere
                    } else if (event.originalEvent && event.originalEvent.type === "mouseup") {
                        // This is an *actual* spinstop
                        var numberValue = Number(widget.spinner("value"));
                        observable(numberValue);
                    }
                });
    
                // handle disposal
                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                    widget.spinner("destroy");
                });
            },
            update: function (element, valueAccessor) {
                // [copies model -> field]
                var widget = $(element);
                var observable = valueAccessor();
                var inputValue = Number(widget.spinner("value"));
                var modelValue = observable();
                if (inputValue !== modelValue) {
                    widget.spinner("value", modelValue);
                }
            }
        };
    }
    ko.bindingHandlers.moneyspin = createSpinner({ numberFormat: 'C0', culture: 'en-GB', min: 0, incremental: true });
    ko.bindingHandlers.intspin = createSpinner({ numberFormat: 'n0', culture: 'en-GB' });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2018-05-26
      • 2012-08-08
      • 2018-08-04
      • 2014-02-13
      • 2013-03-19
      • 1970-01-01
      相关资源
      最近更新 更多