观察者如何找出 Ember.js 中被观察属性的前后值?

Posted

技术标签:

【中文标题】观察者如何找出 Ember.js 中被观察属性的前后值?【英文标题】:How can an observer find out the before and after values of the observed property in Ember.js? 【发布时间】:2012-03-03 08:03:11 【问题描述】:

请查看 ud3323 提供的另一个问题的解决方案:http://jsfiddle.net/ud3323/ykL69/。此解决方案使用红色突出显示更改的值。我还有一个额外的要求:如果该值增加了绿色高光,如果它减少了红色高光。为此,我需要了解观察者的旧值和新值。有没有办法做到这一点?

附: Embers 文档没有说明观察者函数中可用的内容。从这个例子我可以看出,由于观察者是在 itemRowView 中定义的,“this”指向 itemRowView。

【问题讨论】:

【参考方案1】:

我使用计算属性路由到模型的属性并将最后一个值存储在其集合中。

registrationGroup: Em.computed('regionModel.registrationGroup', 
get:->
  @.get('regionModel.registrationGroup')
set:(key, value, oldValue)->
  @.set('lastRegistrationGroup', oldValue)
  @.set('regionModel.registrationGroup', value)
)

【讨论】:

CoffeeScript 中 @ 之后不需要一个点。例如。 @get(). 另外,你为什么使用吸气剂?您是否在防止重写? 我在 CS 中使用点是因为我发现在其中搜索某些调用更容易,而且我还发现它提高了可读性。 Getter 只是为了保持一致性,所以我可以使用相同的属性来获取和设置。【参考方案2】:

beforeObserver 在 Ember 1.10 中一直是 deprecated。

改为使用手动缓存:

doSomething: Ember.observer( 'foo', function() 
  var foo = this.get('foo');
  var oldFoo = this.get('_oldFoo');

  if (foo === oldFoo)  return; 

  // Do stuff here

  this.set('_oldFoo', foo);
)

【讨论】:

当这个观察者没有它订阅的任何属性时,它如何知道何时被解雇?我用 .observes('foo') 尝试了类似的东西,并且 foo 值已经在观察者函数中改变了。 谢谢,我已经用依赖键更新了我的答案。是的,从属值在观察者中是新的。您将其与之前的值进行比较,如果它不同于您知道的值已更改。 好的,我明白了,感谢您的澄清和更新。就我而言,如果新值未定义,我实际上是在使用旧值来设置新值,因此最好使用 setter,因为这样我就不需要存储该值。但我认为这在很多情况下都很有效。【参考方案3】:

看看beforeObservers。 beforeObserver 在属性更改之前触发。因此,如果您在 beforeObserver 中 get 属性,您将拥有更改前的值。您可以使用Ember.addBeforeObserver 或通过observesBefore 函数原型扩展来设置这种类型的观察者。

这将为您提供实现目标所需的一切。我根据您的小提琴创建了以下 JSBin 以在此处进行演示:http://emberjs.jsbin.com/qewudu/2/edit

于 2014 年 10 月 7 日更新以反映 Ember 1.7.x 中的行为。

2015 年 2 月更新:beforeObserver 已被弃用。查看此问题的其他答案。

【讨论】:

Ember.addBeforeObserver 更干净。谢谢卢克! 顺便说一句,我最近注意到函数上有一个observesBefore 扩展,所以代码可以像jsfiddle.net/ye3M2 那样做得更好 我不相信提供的“价值”。我正在测试版本 1.5.1 1.7.0 版中也没有值参数。此解决方案已弃用。【参考方案4】:

使用willInsertElement存储初始值,当值改变时,比较两者:

Quotes.itemRowView = Ember.View.extend(
    tagName: 'tr',

    initialValue: null,

    willInsertElement: function()
        var value = this.get('content').value;
        this.set('initialValue', value); 
    ,

    valueDidChange: function() 
        // only run if updating a value already in the DOM
        if(this.get('state') === 'inDOM') 
            var new_value = this.get('content').value;
            // decreased or increased?
            var color =  (new_value > this.get('initialValue') ) ?
                'green' : 'red' ;
            // store the new value
            this.set('initialValue', new_value);
            // only update the value element color
            Ember.$(this.get('element')).find('.quote-value').css('color', color);
        
    .observes('content.value')
);

看看jsfiddle http://jsfiddle.net/ykL69/15/

【讨论】:

谢谢扎克。这很好用。但是,如果我的理解是正确的,则此代码中存在一个错误。似乎 willInsertElement() 只被调用一次(最初插入元素时)。因此,为了保持颜色正确出现,在 valueDidChange() 结束时,您必须将 initialValue 重新初始化为新值 - 从而确保将下一个更改与该值进行比较。虽然这种方法总体上有效,但视图现在正在成为缓冲值的地方。相反,如果观察者可以提供旧值和新值,代码会简单得多。 更正了我的回答。正如@Luke 所说,beforeObserver 看起来可以达到相同的结果。 View state 是一个内部属性,不应直接从您的任何代码中引用。此外,您可以使用this.$('.quote-value'),而不是使用Ember.$(this.get('element')).find('.quote-value) 请注意:“Quotes.itemRowView”不应该是“Quotes.ItemRowView”,因为它是扩展而不是从 Ember.View 创建的? emberist.com/2012/04/09/naming-conventions.html @iX3 名称无关紧要。但是,是的,约定是对类使用大写字母,对实例使用小写字母。

以上是关于观察者如何找出 Ember.js 中被观察属性的前后值?的主要内容,如果未能解决你的问题,请参考以下文章

如何将观察者方法动态添加到 Ember.js 对象

Ember.js:让组件观察商店物品的值变化

Ember.js入门教程博文汇总

如何在 Ember.js 中创建计算属性以查看单个 Ember Data 属性是不是脏?

观察到的对象无意中被解雇 SwiftUI

如何实现 Mule 消息观察者?