Knockout 扩展器导致 observable 在第一遍时成为 return 其默认值,无论输入如何
Knockout extender causing observable to return its default value on first pass regardless of input
我已经定义了一个名为 model.customDifficultySettings
的视图模型,其中的一部分如下所示。它使用一个名为 precision 的扩展器,它只是 Knockout.js 文档中显示的扩展器示例的重命名版本,用于四舍五入到 X 位小数。
ko.extenders.precision = function(target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko
.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : +newValue,
valueToWrite =
Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
})
.extend({ notify: "always" });
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
model.customDifficultySettings = {
econBase: ko
.observable(0)
.extend({ rateLimit: { timeout: 750 }, precision: 3 }),
};
在稍后的 makeGame()
函数中,我们确保我们的 model.customDifficultySettings.econBase()
可观察值与所选难度值
的值相匹配
model.customDifficultySettings.econBase(
difficultyInfo[model.newGameDifficultyIndex() || 0].econBase
);
console.log(model.customDifficultySettings.econBase());
console.log(difficultyInfo[model.newGameDifficultyIndex() || 0].econBase);
第一个 运行 上的 difficultyInfo[model.newGameDifficultyIndex()].econBase
的值为 0.55。我希望控制台将两者都显示为 0.55,或者如果出现问题,两者都显示为 0。然而,对于可观察对象,返回的是 0,而对于输入其中的值,返回的是 0.55。
如果我在代码具有 运行 后从控制台查询 observable,它 returns 预期值为 0.55。
如果更改难度级别,导致 makeGame()
再次变为 运行,则所有值都设置正确。仅在第一个 运行 出现此问题。
我已经将问题追溯到精度扩展器。移除扩展器,一切都按预期工作。但是由于我刚刚复制了示例代码,所以我并不完全清楚它的作用以及为什么会出现此问题。
作为解决方法,我可以设置所有可观察到的默认值以匹配默认难度级别的值,但我宁愿避免这种情况。
出现问题是因为我先声明了一个 rateLimit
。如果我反转它并首先声明 precision
,那么一切都会按预期进行。所以我的视图模型现在看起来像这样:
model.customDifficultySettings = {
econBase: ko
.observable(0)
.extend({ precision: 3, rateLimit: { timeout: 750 } }),
};
我已经定义了一个名为 model.customDifficultySettings
的视图模型,其中的一部分如下所示。它使用一个名为 precision 的扩展器,它只是 Knockout.js 文档中显示的扩展器示例的重命名版本,用于四舍五入到 X 位小数。
ko.extenders.precision = function(target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko
.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : +newValue,
valueToWrite =
Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
})
.extend({ notify: "always" });
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
model.customDifficultySettings = {
econBase: ko
.observable(0)
.extend({ rateLimit: { timeout: 750 }, precision: 3 }),
};
在稍后的 makeGame()
函数中,我们确保我们的 model.customDifficultySettings.econBase()
可观察值与所选难度值
model.customDifficultySettings.econBase(
difficultyInfo[model.newGameDifficultyIndex() || 0].econBase
);
console.log(model.customDifficultySettings.econBase());
console.log(difficultyInfo[model.newGameDifficultyIndex() || 0].econBase);
第一个 运行 上的 difficultyInfo[model.newGameDifficultyIndex()].econBase
的值为 0.55。我希望控制台将两者都显示为 0.55,或者如果出现问题,两者都显示为 0。然而,对于可观察对象,返回的是 0,而对于输入其中的值,返回的是 0.55。
如果我在代码具有 运行 后从控制台查询 observable,它 returns 预期值为 0.55。
如果更改难度级别,导致 makeGame()
再次变为 运行,则所有值都设置正确。仅在第一个 运行 出现此问题。
我已经将问题追溯到精度扩展器。移除扩展器,一切都按预期工作。但是由于我刚刚复制了示例代码,所以我并不完全清楚它的作用以及为什么会出现此问题。
作为解决方法,我可以设置所有可观察到的默认值以匹配默认难度级别的值,但我宁愿避免这种情况。
出现问题是因为我先声明了一个 rateLimit
。如果我反转它并首先声明 precision
,那么一切都会按预期进行。所以我的视图模型现在看起来像这样:
model.customDifficultySettings = {
econBase: ko
.observable(0)
.extend({ precision: 3, rateLimit: { timeout: 750 } }),
};