为什么以这种方式更改此格式化功能会导致 Knockout 绑定开始工作?
Why did changing this formatting function in this way, cause the Knockout binding to start working?
我在页面上有一个元素,如下所示:
<span data-bind="text: FormattedCountOfPeople"></span>
而计算它的函数我首先是这样写的:
self.FormattedCountOfPeople = ko.computed(function () {
if(!self.PeopleCountFormatString) //a string like "{0} people in the conference", but set by a service call so starts out undefined
return "not set yet";
let sizes = self.Params().PermittedCounts(); //an array of discrete permitted sizes e.g. [2, 10, 30]
let size = self.Params().ChosenCount(); //value set by a jquery slider, could be any double, even 5.7435 - to achieve smooth dragging of the slider it has a small step but snaps to a permitted count
let n = nearest(size, sizes); //a "round to nearest" helper function that given args of e.g. (5.7345, [2, 10, 30]) will pick 2 because 5.7345 is nearer to 2 than 10
let s = self.PeopleCountFormatString.csFormat(n); //csformat is a helper function that performs C# style string Formatting e.g. "{0} people".csFormat(2) -> "2 people"
return s;
});
然后我转了几个小时想知道为什么页面上的文本只是卡在“尚未设置”,无论滑块设置是什么,但 <span data-bind="text: Params().ChosenCount"></span>
添加的另一个元素作为测试, 正在完美更新,而在其他地方,一个不同的滑块正在使用类似的逻辑设置小时和分钟的持续时间:
//if the user picks 61.2345, it rounds to 60, then returns "1 hour". Picking 74.11 rounds to 75 then returns "1 hour, 15 min"
self.FormattedDurationText = ko.computed(function () {
var duration = self.Params().ChosenDuration();
duration = Math.round(duration / 15) * 15;
if (Math.floor(duration / 60) > 0)
var hours = self.DurationTextHours.csFormat(Math.floor(duration / 60));
if (duration % 60 > 0)
var minutes = self.DurationTextMinutes.csFormat(duration % 60);
if (minutes && hours)
return self.DurationTextLayout.csFormat(hours, minutes)
if (hours && !minutes)
return hours;
if (!hours && minutes)
return minutes;
return "";
});
在不同的地方添加一些控制台日志,很明显,在第一次调用返回“尚未设置”的 FormattedCountOfPeople
之后,拖动人数统计时 FormattedCountOfPeople
再也没有被调用过滑块。另一个跨度,直接绑定到原始 Params().ChosenCount
会不断更新,所以值正在改变。类似地,绑定到 Params().ChosenDuration
的滑块正在更新值,并且每次值更改时都会调用 FormattedDuration()
并提供新的格式化字符串以进入 span
最后,使事情正常进行的代码更改似乎微不足道。我删除了初始 if
并将其换成内联条件:
self.FormattedCountOfPeople = ko.computed(function () {
let sizes = self.Params().PermittedCounts();
let size = self.Params().ChosenCount();
let n = nearest(size, sizes);
let s = (self.PeopleCountFormatString ? self.PeopleCountFormatString: "not set yet").csFormat(n);
return s;
为什么进行此更改突然意味着每次值更改时 knockout 都开始调用 FormattedCountOfPeople
?我能看到的唯一真正不同的是 FormattedDurationText
的结构使得它总是调用例如Params().ChosenDuration()
在决定值不好之前和 returns ""
而 FormattedCountOfPeople
的第一个版本有一个行为,偶尔决定不调用任何东西,第二个版本总是调用。调用 Params().Xxx()
是否有副作用,例如“重置标志”,如果标志永远不会重置,即使值发生变化,knockout 也不会再次调用该函数?
当您在计算中引用一个可观察值时,KO 将在内部订阅该可观察值,因此每次可观察值发生变化时都会重新计算计算值。
当您在计算开始时执行此操作时:
if(!self.PeopleCountFormatString)
return "not set yet";
并且 self.PeopleCountFormatString
不是 可观察的(它似乎不是),因为 return 语句,对 ChosenCount
的订阅永远不会发生,并且因为 PeopleCountFormatString
本身也不是可观察的,所以当 PeopleCountFormatString
确实有一个值时,计算不会在以后重新评估。因此,它的值将永远保持“尚未设置”。
更新后的计算有效,因为您立即引用了其他可观察量,因此内部 KO 将订阅这些并在可观察量发生变化时重新评估计算。
我在页面上有一个元素,如下所示:
<span data-bind="text: FormattedCountOfPeople"></span>
而计算它的函数我首先是这样写的:
self.FormattedCountOfPeople = ko.computed(function () {
if(!self.PeopleCountFormatString) //a string like "{0} people in the conference", but set by a service call so starts out undefined
return "not set yet";
let sizes = self.Params().PermittedCounts(); //an array of discrete permitted sizes e.g. [2, 10, 30]
let size = self.Params().ChosenCount(); //value set by a jquery slider, could be any double, even 5.7435 - to achieve smooth dragging of the slider it has a small step but snaps to a permitted count
let n = nearest(size, sizes); //a "round to nearest" helper function that given args of e.g. (5.7345, [2, 10, 30]) will pick 2 because 5.7345 is nearer to 2 than 10
let s = self.PeopleCountFormatString.csFormat(n); //csformat is a helper function that performs C# style string Formatting e.g. "{0} people".csFormat(2) -> "2 people"
return s;
});
然后我转了几个小时想知道为什么页面上的文本只是卡在“尚未设置”,无论滑块设置是什么,但 <span data-bind="text: Params().ChosenCount"></span>
添加的另一个元素作为测试, 正在完美更新,而在其他地方,一个不同的滑块正在使用类似的逻辑设置小时和分钟的持续时间:
//if the user picks 61.2345, it rounds to 60, then returns "1 hour". Picking 74.11 rounds to 75 then returns "1 hour, 15 min"
self.FormattedDurationText = ko.computed(function () {
var duration = self.Params().ChosenDuration();
duration = Math.round(duration / 15) * 15;
if (Math.floor(duration / 60) > 0)
var hours = self.DurationTextHours.csFormat(Math.floor(duration / 60));
if (duration % 60 > 0)
var minutes = self.DurationTextMinutes.csFormat(duration % 60);
if (minutes && hours)
return self.DurationTextLayout.csFormat(hours, minutes)
if (hours && !minutes)
return hours;
if (!hours && minutes)
return minutes;
return "";
});
在不同的地方添加一些控制台日志,很明显,在第一次调用返回“尚未设置”的 FormattedCountOfPeople
之后,拖动人数统计时 FormattedCountOfPeople
再也没有被调用过滑块。另一个跨度,直接绑定到原始 Params().ChosenCount
会不断更新,所以值正在改变。类似地,绑定到 Params().ChosenDuration
的滑块正在更新值,并且每次值更改时都会调用 FormattedDuration()
并提供新的格式化字符串以进入 span
最后,使事情正常进行的代码更改似乎微不足道。我删除了初始 if
并将其换成内联条件:
self.FormattedCountOfPeople = ko.computed(function () {
let sizes = self.Params().PermittedCounts();
let size = self.Params().ChosenCount();
let n = nearest(size, sizes);
let s = (self.PeopleCountFormatString ? self.PeopleCountFormatString: "not set yet").csFormat(n);
return s;
为什么进行此更改突然意味着每次值更改时 knockout 都开始调用 FormattedCountOfPeople
?我能看到的唯一真正不同的是 FormattedDurationText
的结构使得它总是调用例如Params().ChosenDuration()
在决定值不好之前和 returns ""
而 FormattedCountOfPeople
的第一个版本有一个行为,偶尔决定不调用任何东西,第二个版本总是调用。调用 Params().Xxx()
是否有副作用,例如“重置标志”,如果标志永远不会重置,即使值发生变化,knockout 也不会再次调用该函数?
当您在计算中引用一个可观察值时,KO 将在内部订阅该可观察值,因此每次可观察值发生变化时都会重新计算计算值。
当您在计算开始时执行此操作时:
if(!self.PeopleCountFormatString)
return "not set yet";
并且 self.PeopleCountFormatString
不是 可观察的(它似乎不是),因为 return 语句,对 ChosenCount
的订阅永远不会发生,并且因为 PeopleCountFormatString
本身也不是可观察的,所以当 PeopleCountFormatString
确实有一个值时,计算不会在以后重新评估。因此,它的值将永远保持“尚未设置”。
更新后的计算有效,因为您立即引用了其他可观察量,因此内部 KO 将订阅这些并在可观察量发生变化时重新评估计算。