我已经在敲除中创建了以下绑定处理程序
所需的功能是,如果字段是数字字段,则在显示时将其格式化为小数点后的"X"位(默认为2),但基本值是所输入的值。
一切都很好,但我想添加一个功能,当输入集中时,它会显示实际值,我只是不知道如何做到这一点。
即
- 用户在输入中输入1.1121
- 当他们离开输入时,它的格式为1.11
- 如果它们返回到输入(焦点),则显示1.1121进行编辑
我不知道如何实现第3点,因为目前它显示1.11,然后在模糊上过度写入??
有人能告诉我正确的方向吗?基本上,我在哪里访问焦点上的基本值,并用基本值替换显示的文本??
为了简洁起见,我删除了一些其他的"装饰"代码,这些代码包装了输入,因为它们不是相关的。
提前谢谢。
ko.bindingHandlers.specialInput = {
init: function (element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor();
var decimals = allBindingsAccessor().decimals || 2;
var formatString = "";
var interceptor = ko.computed({
read: function () {
if(isNumeric(ko.unwrap(value))){
//to do if time - replace this with a function that will accept any number of decimals
if(decimals == 0){
formatString = "0,0";
}
if(decimals == 1){
formatString = "0,0.0";
}
if(decimals == 2){
formatString = "0,0.00";
}
if(decimals == 3){
formatString = "0,0.000";
}
if(decimals == 4){
formatString = "0,0.0000";
}
if(decimals == 5){
formatString = "0,0.00000";
}
return numeral(ko.unwrap(value)).format(formatString);
}else{
return ko.unwrap(value);
}
},
write: function (newValue) {
if ($.trim(newValue) == '')
value("");
else
if(isNumeric(newValue)){
value(numeral().unformat(newValue));
value.valueHasMutated();
}else{
value(newValue);
value.valueHasMutated();
}
}
}).extend({notify: 'always'});
if (element.tagName.toLowerCase() == 'input') {
ko.applyBindingsToNode(element, {
value: interceptor
});
} else {
ko.applyBindingsToNode(element, {
text: interceptor
});
}
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.unwrap(valueAccessor());
return ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
}
};
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
我不会用计算的interceptor
来实现这一点。
我宁愿做以下事情:
在init
中,在init:中为focus
和blur
注册事件处理程序
- 在
focus
处理程序上,必须在输入中显示基础值 - 在
blur
处理程序中,必须将数字存储在文本框中,并在输入中显示四舍五入的值
在update
中,您必须存储实际值,并将其显示在文本框中。更新值时,文本框很可能没有焦点,因此应该安全地显示舍入值。然而,如果你认为在某些情况下它可以被聚焦,你可以这样做来测试它,以决定如何显示值:使用jQuery来测试输入是否有焦点
伪代码
ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
$element.on('focus', function() {
// Show raw value:
$element.val(/* raw value */);
});
$element.on('blur', function() {
// Update the observable with the value in the input
ko.unwrap(valueAccessor())( /* get raw value from input */);
// Show the rounded value
$element.val(/* rounded value */);
});
// Update will be called after init when the binding is first applied,
// so you don't have to worry about what it's initially shown
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// When the value changes, show it in the input
$.element.val(/* if focused show raw, if not, show roundede*/);
}
};
如果您确信只将其与input
和可写可观察器一起使用,则此代码是安全的。如果你对此有疑问,你应该添加很多检查,比如检查使用jQuery .val()
或.text()
的元素类型,检查绑定表达式是否是可写的可观察值以更新其值,等等
注意:有一件事需要多次监督:当元素被破坏时,处理我们不再需要的对象(例如,"if"、"whit"或"template"可能会发生这种情况)。在这种情况下,我认为你不需要这样做,但是,请看这个:如果你认为你需要销毁一些东西,那么自定义处理逻辑。
在绑定处理程序中使用jQuery没有错,但您也可以简单地使用现有的绑定处理程序。这是一种可以被卷成一个组件来重复使用的东西(尽管我在示例中没有这样做)。
您只需要为您的值提供一个后备存储,计算的返回后备存储或格式化的后备存储,这取决于输入是否具有焦点(使用hasFocus
绑定)。
vm = (function() {
var editing = ko.observable(false),
backingStore = 0,
value = ko.computed({
read: function() {
return editing() ? backingStore : (+backingStore).toFixed(2);
},
write: function(newValue) {
backingStore = newValue;
}
});
return {
editing: editing,
value: value
}
}());
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="hasFocus: editing, value: value" />
<input />