【问题标题】:Get new value of an observable in "beforeChange" subscription在“beforeChange”订阅中获取可观察的新值
【发布时间】: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

标签: knockout.js knockout-2.0


【解决方案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、绑定等。如果您想在任何这些通知之前做某事,您有几个选择。

  1. 正如@user3297291 所说,使用Ryan Niemeyer 的protectedObservable

  2. 在任何其他订阅之前立即订阅 observable。订阅者始终按顺序调用,因此您的代码将始终在其他任何内容之前运行。

  3. 覆盖notifySubscribers以挂钩通知过程(记得调用上一个方法)。

  4. 可能对于 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);
    };
    

    【讨论】:

      猜你喜欢
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-26
      • 2018-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多