我想使用以下技术:在敲除
上制作仅输入单数允许用户只输入数字。
但是,此技术不会更新UI上可观察的值。
html:
<span data-bind="text: Interval" ></span>
<input data-bind="numeric: Interval" />
绑定:
ko.bindingHandlers.numeric = {
init: function (element, valueAccessor) {
$(element).on("keydown", function (event) {
// Allow: backspace, delete, tab, escape, and enter
if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
// Allow: Ctrl+A
(event.keyCode == 65 && event.ctrlKey === true) ||
// Allow: . ,
(event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
// Allow: home, end, left, right
(event.keyCode >= 35 && event.keyCode <= 39)) {
// let it happen, don't do anything
return;
}
else {
// Ensure that it is a number and stop the keypress
if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
event.preventDefault();
}
}
});
}
};
因此,绑定不允许输入数字以外的字符,但是当焦点在input
上丢失时,相应的观察值不会更新(因此span
元素没有更改)。
注意:
我不需要允许用户将非数字字符输入输入。我知道还有其他解决方案,例如KO数字扩展程序可以将所有内容转换为数字,但我不需要。我需要一个允许仅输入数字的解决方案(包括诸如Backspace等)。
这将执行您想要的事情:
<span data-bind="text: Interval" ></span>
<input data-bind="numeric, value: Interval" />
http://jsfiddle.net/mbest/n4z8q/
数字数字的坚实途径是用户使用扩展器。
我们不必跟踪按键。只需订阅可观察到的值之前,它就更容易了。然后,我们可以做一些以下等级,使我们能够评估输入是否为数字。如果输入不是数字,我们将剥离非数字字符。因此不允许非数字输入。
小提琴:
html
<input type="text" data-bind="value: myNum, valueUpdate: 'afterkeyup'" />
JS
(function(ko) {
ko.observable.fn.numeric = function () {
// the observable we are extending
var target = this;
// subscribe to the observable so we can
// intercept the value and do our custom
// processing.
this.subscribe(function() {
var value = target();
// this will strip out any non numeric characters
target(value.replace(/[^0-9]+/g,'')); //[^0-9.]/g - allows decimals
}, this);
return target;
};
function ViewModel() {
this.myNum = ko.observable().numeric();
};
ko.applyBindings(new ViewModel());
})(ko);
我建议您围绕http://numeraljs.com/制作包装器。您只需连接设置,然后在更新时您将在输入上调用格式。
这是我的固定版本,考虑到上面的所有版本,但是作为实际值绑定和>支持非观察到的对象作为源/目标。
edit :敲除的缩小版本不会公开 writevaluetoperty 函数和 twowaybindings 。因此,我们应该克隆写入valuetoperty 并使用 _twowayBindings 。我更新了代码以支持淘汰的缩小版本。
ko.expressionRewriting._twoWayBindings.numericValue = true;
ko.expressionRewriting.writeValueToProperty = function (property, allBindings, key, value, checkIfDifferent) {
if (!property || !ko.isObservable(property)) {
var propWriters = allBindings.get('_ko_property_writers');
if (propWriters && propWriters[key])
propWriters[key](value);
} else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
property(value);
}
};
ko.bindingHandlers.numericValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
$(element).on("keydown", function (event) {
// Allow: backspace, delete, tab, escape, and enter.
if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
// Allow: Ctrl+A
(event.keyCode == 65 && event.ctrlKey === true) ||
// Allow: . ,
(event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
// Allow: home, end, left, right.
(event.keyCode >= 35 && event.keyCode <= 39)) {
// Let it happen, don't do anything.
return;
}
else {
if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
event.preventDefault();
}
}
});
var underlying = valueAccessor();
var interceptor = ko.dependentObservable({
read: function () {
if (ko.isObservable(underlying) == false) {
return underlying;
} else {
return underlying();
}
},
write: function (value) {
if (ko.isObservable(underlying) == false) {
if (!isNaN(value)) {
var parsed = parseFloat(value);
ko.expressionRewriting.writeValueToProperty(underlying, allBindingsAccessor, 'numericValue', !isNaN(parsed) ? parsed : null);
}
} else {
if (!isNaN(value)) {
var parsed = parseFloat(value);
underlying(!isNaN(parsed) ? parsed : null);
}
}
}
});
ko.bindingHandlers.value.init(element, function () { return interceptor; }, allBindingsAccessor, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
}
}
确实,这无法更新您的可观察到。自定义绑定是不完整的。在我看来,这只是作为一个想法的一个例子,而不是一个有效的解决方案。
但是,在您链接的问题中,评论中某个地方实际上有一个更好的方法。它是使用敲除扩展器。请参阅http://knockoutjs.com/documentation/extenders.html
上的实时示例1有几个原因更好: 1.更健壮。例如,您仍然可以在解决方案中的剪贴板中粘贴一串文本。 2.更加用户友好。您的解决方案明确禁用了一堆键。这根本不是用户友好的。敲除提出的解决方案仅确保最终值是正确的。 3.更好的代码分离和可维护性:您的HTML只能包含一个普通的价值绑定。一旦要求该值应该是数值,您只需在视图模型中扩展可观察到的。您所做的唯一更改是在JavaScript中,因为它的功能而不是呈现。更改也是自身的,很明显,扩展器对可能在计算中使用可观察到的任何人做什么。
我需要一个允许输入数字的解决方案(包括 诸如Backspace等。)。
检查此jQuery插件:http://www.texotela.co.uk/code/jquery/numeric/
它允许十进制分离器,您可能需要分叉,以便允许其他字符,例如Backspace
您可以改进绑定处理程序,以支持ValueAccessor的修改
绑定:
ko.bindingHandlers.numeric = {
init: function (element, valueAccessor) {
var value = valueAccessor();
$(element).on("keydown", function (event) {
// Allow: backspace, delete, tab, escape, and enter
if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
// Allow: Ctrl+A
(event.keyCode == 65 && event.ctrlKey === true) ||
// Allow: . ,
(event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
// Allow: home, end, left, right
(event.keyCode >= 35 && event.keyCode <= 39)) {
// let it happen, don't do anything
return;
}
else {
// Ensure that it is a number and stop the keypress
if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
event.preventDefault();
}
}
});
$(element).change(function () {
value($(element).val());
});
}
};
在这种情况下,html将为
<span data-bind="text: Interval" ></span>
<input data-bind="numeric: Interval" />
小提琴