Ember
可以檢測任何屬性的變化,包括計算屬性。
Ember
可以察覺所有屬性的變化,包括計算屬性。觀察者是非常有用的,特別是計算屬性綁定之后需要同步的時候。
觀察者經(jīng)常被Ember開發(fā)過度使用。Ember
框架本身已經(jīng)大量使用觀察者,但是對于大多數(shù)的開發(fā)者面對開發(fā)問題時使用計算屬性是更適合的解決方案。
使用方式:可以用Ember.observer
創(chuàng)建一個對象為觀察者。
// Observer對于Emberjs來說非常重要,前面你看到的很多代碼都是與它有關系,計算屬性之所以能更新也是因為它
Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + " " + this.get('lastName');
}),
// 當fullName被改變的時候觸發(fā)觀察者
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'
});
// 如果被觀察的計算屬性還沒執(zhí)行過get()方法不會觸發(fā)觀察者
console.log('fullName = ' + person.get('fullName'));
// fullName是依賴firstName和lastName的,這里改變了firstName的值,計算屬性會自動更新,
// fullName被改變了所以會觸發(fā)觀察者
person.set('firstName', 'change firstName value'); // 觀察者會被觸發(fā)
console.log('fullName = ' + person.get('fullName'));
fullName
是依賴firstName
和lastName
的,調(diào)用set()
方法改變了firstName
的值,自然的導致fullName
的值也被改變了,fullName
變化了就觸發(fā)觀察者。從執(zhí)行的結(jié)果就可以看出來;
Ember
還為開發(fā)者提供了另一種使用觀察者的方式。這種方式使你可以在類定義之外為某個計算屬性增加一個觀察者。
person.addObserver('fullName', function() {
// deal with the change…
});
目前,觀察者在Ember
中是同步的(不是筆誤,官網(wǎng)就是這么說的Observers in Ember are currently synchronous.
)。這就意味著只要計算屬性一發(fā)生變化就會觸發(fā)觀察者。也因為這個原因很容易就會引入這樣的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'));
})
});
然而由于同步的原因如果你的的觀察者同時觀察多個屬性,就會導致觀察者執(zhí)行多次。
person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + " " + this.get('lastName');
}),
// 當fullName被改變的時候觸發(fā)觀察者
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]');
顯然上述代碼執(zhí)行了兩次set()
所以觀察者也會執(zhí)行2次,但是如果開發(fā)中需要設置只能執(zhí)行一次觀察出呢?Ember提供了一個once()
方法,這個方法會在下一次循環(huán)所有綁定屬性都同步的時候執(zhí)行。
Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + " " + this.get('lastName');
}),
// 當fullName被改變的時候觸發(fā)觀察者
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本身還是會執(zhí)行多次,但是方法processFullName只會執(zhí)行一次
console.log('========partOfNameChanged======'); //
Ember.run.once(this, 'processFullName');
}),
processFullName: Ember.observer('fullName', function() {
// 當你同時設置多個屬性的時候,此觀察者只會執(zhí)行一次,并且是發(fā)生在下一次所有屬性都被同步的時候
console.log('fullName = ' + this.get('fullName'));
})
});
var person = Person.create({
firstName: 'chen',
lastName: 'ubuntuvim'
});
person.set('firstName', '[firstName]');
person.set('lastName', '[lastName]');
觀察者一直到對象初始化完成之后才會執(zhí)行。
如果你想觀察者在對象初始化的時候就執(zhí)行你必須要手動調(diào)用Ember.on()
方法。這個方法會在對象初始化之后就執(zhí)行。
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......
如果一個計算屬性從來沒有調(diào)用過get()
方法獲取的其值,觀察者就不會被觸發(fā),即使是計算屬性的值發(fā)生變化了。你可以這么認為,觀察者是根據(jù)調(diào)用get()
方法前后的值比較判斷出計算屬性值是否發(fā)生改變了。如果沒調(diào)用過get()
之前的改變觀察者認為是沒有變化。
通常我們不需要擔心這個問題會影響到程序代碼,因為幾乎所有被觀察的計算屬性在觸發(fā)前都會執(zhí)行取值操作。如果你仍然擔心觀察者不會被觸發(fā),你可以在init()
方法了執(zhí)行一次get
操作。這樣足以保證你的觀察在觸發(fā)之前是執(zhí)行過get操作的。
對于初學者來說,屬性值的自動更新還是有點難以理解,到底它是怎么個更新法?。?!先別急,先放一放,隨著不斷深入學習你就會了解到這個是多么強大的特性。
博文完整代碼放在Github(博文經(jīng)過多次修改,博文上的代碼與github代碼可能又出入,不過影響不大?。绻阌X得博文對你有點用在github項目上給我個star
吧。您的肯定對我來說是最大的動力??!
更多建議: