在“beforeChange”订阅中获取可观察的新值
Posted
技术标签:
【中文标题】在“beforeChange”订阅中获取可观察的新值【英文标题】:Get new value of an observable in "beforeChange" subscription 【发布时间】:2017-05-13 12:51:11 【问题描述】:我知道get the new value of an observable in a subscribe event 有解决方案(在实际更改之后),但我想知道是否可以在“beforeChange”订阅中访问 observable 的新值。
下面是current version of Knockout (3.4.1) 的 sn-p,分别使用旧值和新值引发 beforeChange 和 afterChange 订阅处理程序:
if (computedObservable.isDifferent(state.latestValue, newValue))
if (!state.isSleeping)
computedObservable["notifySubscribers"](state.latestValue, "beforeChange");
state.latestValue = newValue;
if (DEBUG) computedObservable._latestValue = newValue;
if (state.isSleeping)
computedObservable.updateVersion();
else if (notifyChange)
computedObservable["notifySubscribers"](state.latestValue);
changed = true;
显然 newValue 在“beforeChange”中可用,所以我想分叉是一种选择,但我不想这样做。
有没有其他解决方案来获得这个新值“beforeChange”?
【问题讨论】:
您能否详细说明为什么要在设置新值之前获取它? @MichaelBest 我试图阻止 FOUC。当我能够在实际设置之前读取新值时,我可以更新一些其他状态以防止不需要的视图中间渲染 您应该能够使用计算或订阅来更新可用于隐藏/显示/样式的第二个可观察对象。例如:jsfiddle.net/dmnqoc53 【参考方案1】:编辑:我刚刚重读了您的问题,并认为您的意思可能是您想在 设置新值之前检查它?如果是这种情况,您可能想要执行this 之类的操作。
我通常创建两个订阅和一个额外的变量来跟踪旧的(您可能已经尝试过):
var myObs = ko.observable(1);
// Keep track of old
var myObsOld = myObs();
myObs.subscribe(function(oldVal)
myObsOld = oldVal;
, null, "beforeChange");
// Subscribe to new
myObs.subscribe(function(newVal)
console.log("myObs changed from", myObsOld, "to", newVal);
);
myObs(2);
myObs(3);
.as-console-wrapper min-height: 100%;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
现在,如果您不想在视图模型中添加额外的变量和订阅,可以将此逻辑封装在扩展器中:
ko.extenders.latestValue = function(target, option)
target.latestValue = target();
target.subscribe(function(oldVal)
target.latestValue = oldVal;
, null, "beforeChange");
return target;
;
var myObs2 = ko.observable("a").extend( latestValue: true );
myObs2.subscribe(function(newVal)
console.log("myObs2 changed from", myObs2.latestValue, "to", newVal);
);
myObs2("b");
myObs2("c");
.as-console-wrapper min-height: 100%;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
不是一个非常性感的方法,但我认为这比分叉回购更好:)
【讨论】:
感谢您的回答。实际上,我的问题是在实际更改之前检索新值,而不是在更改后检索旧值。包装 observable 会是什么样子?如何订阅?。【参考方案2】:注意:此答案基于您对问题的评论,而不是原始问题。
当一个 observable 发生变化时,它会调用 observable 上的一个名为 notifySubscribers
的方法,该方法会执行实际通知,从而更新依赖于该 observable 的任何计算出的 observable、绑定等。如果您想在任何这些通知之前做某事,您有几个选择。
正如@user3297291 所说,使用Ryan Niemeyer 的protectedObservable。
在任何其他订阅之前立即订阅 observable。订阅者始终按顺序调用,因此您的代码将始终在其他任何内容之前运行。
覆盖notifySubscribers
以挂钩通知过程(记得调用上一个方法)。
可能对于 Knockout 3.5.0,在 change
事件之前会出现 a spectate
event。
【讨论】:
【参考方案3】:这并不完全是对您请求的响应,但可能对稍微不同的用例有用。
如果您不坚持在更改传播到可观察对象之前调用订阅,并与 beforeChange 订阅一起触发,则可以创建自己的订阅,将新旧值一起推送到回调。
此订阅在更改发生后触发,它只是同时提供以前和当前的值。
/**
* extended version of knockout subscription provides to callback function new and previous value at once
* function Callback(newValue, originalValue) ...
*
* @param Function callback function called on observable change
* @param Object context of the callback
* @return Object instance of changed subscription
*/
ko.subscribable.fn.subscribeChanged = function (callback, context)
var savedValue = this.peek();
return this.subscribe(function (latestValue)
var oldValue = savedValue;
savedValue = latestValue;
callback(latestValue, oldValue);
, context);
;
【讨论】:
以上是关于在“beforeChange”订阅中获取可观察的新值的主要内容,如果未能解决你的问题,请参考以下文章