我正在尝试使用KnockoutJS实现类型安全的ViewModel。在我开始通过HTML输入标签更新observable之前,它工作得非常好。
我已经实现了type
扩展程序,它返回计算的observable:
return ko.computed({
read: target,
write: fixer
})
fixer
类似于:
function (newValue) {
var current = target(),
valueToWrite = (newValue == null ? null : fixNumber(newValue, 0));
if (valueToWrite !== current) target(valueToWrite);
else if (newValue !== current) target.notifySubscribers(valueToWrite);
}
fixNumber
是
function fixNumber(value, precision) {
if (value == null || value === '') return null;
var newValue = (value || '').toString().replace(/^[^\,\.\d\-]*([\.\,\-]?\d*)([\,\.]?\d*).*$/, '$1$2').replace(/\,/, '.'),
valueToWrite = Number(newValue);
return !!(valueToWrite % 1) ? round(valueToWrite, precision) : valueToWrite;
}
看起来不是那么简单,但我必须考虑使用逗号作为小数分隔符。
一旦用户按下键以立即反映此更改,我通常需要更新我的observable:
<input type="text" data-bind="value: nonThrottled, valueUpdate: 'afterkeyup'"></input>
这里出现了很多问题,例如,我不能在那里输入小于1(0.1,0.2等)的十进制值。
当我试图扼杀一个观察者时,它大部分都有效。但有时用户输入和类型修复程序不同步,所以看起来有些输入偶尔会丢失。
完整的例子是http://jsfiddle.net/mailgpa/JHztW/。我真的很感激任何提示,因为我花了好几天时间来解决这些问题。
我解决了提供自定义value
绑定的问题,所以现在受限制的observables偶尔不会吃掉我的输入。
我添加了额外的valueThrottle选项绑定来限制元素值的更新:
var valueThrottle = allBindingsAccessor()["valueThrottle"];
var valueThrottleTimeoutInstance = null;
/* ... */
if (valueThrottle) {
clearTimeout(valueThrottleTimeoutInstance);
valueThrottleTimeoutInstance = setTimeout(function () {
ko.selectExtensions.writeValue( element, ko.utils.unwrapObservable(valueAccessor()) );
}, valueThrottle);
} else applyValueAction();
另外我注意到在我的情况下无法输入0.2这样的值来自原始value
绑定中的声明:
if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
valueHasChanged = true;
我把它重写为
if ((newValue === 0) && (elementValue != 0))
valueHasChanged = true;
至少在Chrome上有效,但我没有正确测试,甚至不确定它是否正确。
要添加示例,由于某种原因,jsFiddle不接受我的自定义绑定。
任何评论都非常感谢。