×

EmberJS 教程

EmberJS 概述EmberJS 环境配置EmberJS 应用EmberJS 对象模型EmberJS 模板EmberJS 路由器EmberJS 组件EmberJS 模型EmberJS 视图EmberJS 控制器EmberJS 测试EmberJS 指定查询参数

Ember 对象模型

Ember 类的定义 初始化 继承Ember 类的扩展Ember 计算属性Ember 观察者Ember 数据绑定Ember 枚举Ember 第一章对象模型小结

Ember handlebars模板

Ember handlebars基础Ember handlebars条件表达式Ember handlebars遍历标签Ember handlebars显示对象键Ember handlebars属性绑定Ember {{link-to}} 助手Ember 路由 模板执行渲染顺序Ember {{action}} 助手Ember 表单元素Ember 调试助手Ember 工具类的助手Ember 第二章模板小结

Ember 路由

Ember 路由定义Ember 指定与路由关联的模型Ember 模板渲染Ember 路由重定向Ember 路由终止挑战和激活Ember loading error子路由Ember 查询参数Ember 异步路由

Ember 组件

Ember 组件定义Ember 属性传递Ember 包裹内容自定义包裹组件的HTML标签Ember 处理事件Ember action触发变化

Ember 控制器

Ember 控制器Ember 管理控制器的依赖关系

Ember 模型

Ember model简介Ember 定义模型Ember 记录查询Ember 新建、更新、删除记录Ember 设置记录到StoreEmber model的关联关系处理Ember 元数据Ember 自定义适配器Ember 自定义序列号器

Ember 测试

Ember 测试简介Ember 验收测试Ember 单元测试

Ember 观察者


Ember可以检测任何属性的变化,包括计算属性。

观察者使用

Ember可以察觉所有属性的变化,包括计算属性。观察者是非常有用的,特别是计算属性绑定之后需要同步的时候。 观察者经常被Ember开发过度使用。Ember框架本身已经大量使用观察者,但是对于大多数的开发者面对开发问题时使用计算属性是更适合的解决方案。 使用方式:可以用Ember.observer创建一个对象为观察者。

// Observer对于Emberjs来说非常重要,前面你看到的很多代码都是与它有关系,计算属性之所以能更新也是因为它
Person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});

var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});
// 如果被观察的计算属性还没执行过get()方法不会触发观察者
console.log('fullName = ' + person.get('fullName'));  
//  fullName是依赖firstName和lastName的,这里改变了firstName的值,计算属性会自动更新,
//  fullName被改变了所以会触发观察者
person.set('firstName', 'change firstName value');  // 观察者会被触发
console.log('fullName = ' + person.get('fullName'));

fullName是依赖firstNamelastName的,调用set()方法改变了firstName的值,自然的导致fullName的值也被改变了,fullName变化了就触发观察者。从执行的结果就可以看出来;

运行结果图

Ember还为开发者提供了另一种使用观察者的方式。这种方式使你可以在类定义之外为某个计算属性增加一个观察者。

person.addObserver('fullName', function() {
    // deal with the change…
});

观察者与异步

目前,观察者在Ember中是同步的(不是笔误,官网就是这么说的Observers in Ember are currently synchronous.)。这就意味着只要计算属性一发生变化就会触发观察者。也因为这个原因很容易就会引入这样的bug在计算属性没有同步的时候。比如下面的代码;

Person.reopen({
  lastNameChanged: Ember.observer('lastName', function() {
    // The observer depends on lastName and so does fullName. Because observers
    // are synchronous, when this function is called the value of fullName is
    // not updated yet so this will log the old value of fullName
    console.log(this.get('fullName'));
  })
});

然而由于同步的原因如果你的的观察者同时观察多个属性,就会导致观察者执行多次。

person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});
Person.reopen({
  partOfNameChanged: Ember.observer('firstName', 'lastName', function() {
    //  同时观察了firstName和lastName两个属性
    console.log('========partOfNameChanged======');
  })
});
var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});

person.set('firstName', '[firstName]');
person.set('lastName', '[lastName]');

run result

显然上述代码执行了两次set()所以观察者也会执行2次,但是如果开发中需要设置只能执行一次观察出呢?Ember提供了一个once()方法,这个方法会在下一次循环所有绑定属性都同步的时候执行。

Person = Ember.Object.extend({
  firstName: null,
  lastName: null,

  fullName: Ember.computed('firstName', 'lastName', function() {
    return this.get('firstName') + " " + this.get('lastName');
  }),

  //  当fullName被改变的时候触发观察者
  fullNameChange: Ember.observer('fullName', function() {
    console.log("The fullName is changed by caller");
    //return this.get('fullName');
  })
});
Person.reopen({
  partOfNameChanged: Ember.observer('firstName', 'lastName', function() {
    //  同时观察了firstName和lastName两个属性
    //  方法partOfNameChanged本身还是会执行多次,但是方法processFullName只会执行一次
    console.log('========partOfNameChanged======');  //  
    Ember.run.once(this, 'processFullName');
  }),
  processFullName: Ember.observer('fullName', function() {
    // 当你同时设置多个属性的时候,此观察者只会执行一次,并且是发生在下一次所有属性都被同步的时候
    console.log('fullName = ' + this.get('fullName'));
  })
});

var person = Person.create({
  firstName: 'chen',
  lastName: 'ubuntuvim'
});

person.set('firstName', '[firstName]');
person.set('lastName', '[lastName]');

run result

观察者与对象初始化

观察者一直到对象初始化完成之后才会执行。 如果你想观察者在对象初始化的时候就执行你必须要手动调用Ember.on()方法。这个方法会在对象初始化之后就执行。

Person = Ember.Object.extend({
  salutation:null,
  init() {
    this.set('salutation', 'hello');
    console.log('init....');
  },
  salutationDidChange: Ember.on('init', Ember.observer('salutation', function() {
    console.log('salutationDidChange......');
  }))
});

var p = Person.create();
p.get('salutationDidChange');  //  output > init....  salutationDidChange......
console.log(p.get('salutation'));  // output > hello
p.set('salutation');  //  output > salutationDidChange......

未获取过值的计算属性不会触发观察者

如果一个计算属性从来没有调用过get()方法获取的其值,观察者就不会被触发,即使是计算属性的值发生变化了。你可以这么认为,观察者是根据调用get()方法前后的值比较判断出计算属性值是否发生改变了。如果没调用过get()之前的改变观察者认为是没有变化。 通常我们不需要担心这个问题会影响到程序代码,因为几乎所有被观察的计算属性在触发前都会执行取值操作。如果你仍然担心观察者不会被触发,你可以在init()方法了执行一次get操作。这样足以保证你的观察在触发之前是执行过get操作的。
对于初学者来说,属性值的自动更新还是有点难以理解,到底它是怎么个更新法!!!先别急,先放一放,随着不断深入学习你就会了解到这个是多么强大的特性。


分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)