我正在尝试使用 KnockoutJS 实现类型安全的 ViewModel 之类的东西。在我开始通过 HTML 输入标签更新 observables 之前,它工作得很好。
我已经实现了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;
}
它看起来不是那么简单,但我必须考虑可能使用逗号作为小数分隔符。
通常,一旦用户按下键以立即反映此更改,我需要立即更新我的 observables:
<input type="text" data-bind="value: nonThrottled, valueUpdate: 'afterkeyup'"></input>
这里有很多问题,例如,我不能在那里输入小于 1 的十进制值(0.1、0.2 等)。
当我尝试限制 observable 时,它主要是有效的。但有时用户输入和类型修复程序会不同步,因此看起来某些输入偶尔会丢失。
完整的例子是http://jsfiddle.net/mailgpa/JHztW/。我真的很感激任何提示,因为我花了几天时间试图解决这些问题。
2013 年 11 月 4 日更新
我解决了提供自定义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 不接受我的自定义绑定。
任何评论都非常感谢。