簡(jiǎn)單地來(lái)說(shuō),計(jì)算屬性就是將函數(shù)聲明為屬性,就類(lèi)似于調(diào)用了一個(gè)函數(shù),Ember
會(huì)自動(dòng)調(diào)用這個(gè)函數(shù)。計(jì)算屬性最大的特點(diǎn)就是能自動(dòng)檢測(cè)變化,及時(shí)更新數(shù)據(jù)。
Person = Ember.Object.extend({
firstName: null,
lastName: null,
// fullName 就是一個(gè)計(jì)算屬性
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + ", " + this.get('lastName');
})
});
// 實(shí)例化同時(shí)傳入?yún)?shù)
var piter = Person.create({
firstName: 'chen',
lastName: 'ubuntuvim'
});
console.log(piter.get('fullName')); // output >> chen, ubuntuvim
計(jì)算屬性其實(shí)就是一個(gè)函數(shù),如果你接觸過(guò)就jQuery、Extjs
相信你會(huì)非常熟悉,在這兩個(gè)框架中函數(shù)就是這么定義的。只不過(guò)在Ember
中,把這種函數(shù)當(dāng)做屬性來(lái)處理,并且可以通過(guò)get獲取函數(shù)的返回值。
在Ember
程序中,計(jì)算屬性還能調(diào)用另外一個(gè)計(jì)算屬性,形成計(jì)算屬性鏈,也可以用于擴(kuò)展某個(gè)方法。在上一實(shí)例的基礎(chǔ)上增加一個(gè)description()
方法。
Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
county: null,
// fullName 就是一個(gè)計(jì)算屬性
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + ", " + this.get('lastName');
}),
description: Ember.computed('fullName', 'age', 'county', function() {
return this.get('fullName') + " age " + this.get('age') + " county " + this.get('county');
})
});
// 實(shí)例化同時(shí)傳入?yún)?shù)
var piter = Person.create({
firstName: 'chen',
lastName: 'ubuntuvim',
age: 25,
county: 'china'
});
console.log(piter.get('description')); // output >> chen, ubuntuvim
當(dāng)用戶(hù)使用set
方法改變firstName
的值,然后再調(diào)用get('description')
得到的值也是更新后的值。
注意要把重寫(xiě)的屬性作為參數(shù)傳入computed
方法,要區(qū)別計(jì)算屬性的定義方法,定義的時(shí)候computed
方法的最后一個(gè)參數(shù)是一個(gè)function
,而重寫(xiě)的時(shí)候最后一個(gè)參數(shù)是一個(gè)hash
。
// 重寫(xiě)計(jì)算屬性的get、set方法
Person = Ember.Object.extend({
firstName: null,
lastName: null,
// 重寫(xiě)計(jì)算屬性fullName的get、set方法
fullName: Ember.computed('firstName', 'lastName', {
get(key) {
return this.get('firstName') + "," + this.get('lastName');
},
set(key, value) {
// 這個(gè)官方文檔使用的代碼,但是我運(yùn)行的時(shí)候出現(xiàn) Uncaught SyntaxError: Unexpected token [ 這個(gè)錯(cuò)誤,不知道是否是缺少某個(gè)文件,后續(xù)會(huì)補(bǔ)上;
// console.log("value = " + value);
// var [ firstName, lastName ] = value.split(/\s+/);
var firstName = value.split(/\s+/)[0];
var lastName = value.split(/\s+/)[1];
this.set('firstName', firstName);
this.set('lastName', lastName);
}
}),
// 對(duì)于普通的屬性無(wú)法重寫(xiě)get、set方法
// firstName: Ember.computed('firstName', {
// get(key) {
// return this.get('firstName') + "@@";
// },
// set(key, value) {
// this.set('firstName', value);
// }
// })
});
var jack = Person.create();
jack.set('fullName', "james kobe");
console.log(jack.get('firstName'));
console.log(jack.get('lastName'));
我們經(jīng)常會(huì)遇到這種情況:某個(gè)計(jì)算屬性值是依賴(lài)某個(gè)數(shù)組或者其他對(duì)象的,比如在Ember
的todos
這個(gè)例子中有這樣的一段代碼。
export default Ember.Controller.extend({
todos: [
Ember.Object.create({ isDone: true }),
Ember.Object.create({ isDone: false }),
Ember.Object.create({ isDone: true })
],
remaining: Ember.computed('todos.@each.isDone', function() {
var todos = this.get('todos');
return todos.filterBy('isDone', false).get('length');
})
});
計(jì)算屬性remaining
的值于依賴(lài)數(shù)組todos
。在這里還有個(gè)知識(shí)點(diǎn):在上述代碼computed()
方法里有一個(gè)todos.@each.isDone
這樣的鍵,里面包含了一個(gè)特別的鍵@each
(后面還會(huì)看到更特別的鍵[]
)。需要注意的是這種鍵不能嵌套并且是只能獲取一個(gè)層次的屬性。比如todos.@each.foo.name
(獲取多層次屬性,這里是先得到foo再獲取name
)或者todos.@each.owner.@each.name
(嵌套)這兩種方式都是不允許的。
在如下4種情況Ember
會(huì)自動(dòng)更新綁定的計(jì)算屬性值:<br>
1.在todos
數(shù)組中任意一個(gè)對(duì)象的isDone
屬性值發(fā)生變化的時(shí)候;
2.往todos
數(shù)組新增元素的時(shí)候;
3.從todos
數(shù)組刪除元素的時(shí)候;
4.在控制器中todos
數(shù)組被改變?yōu)槠渌臄?shù)組的時(shí)候;
比如下面代碼演示的結(jié)果;
Task = Ember.Object.extend({
isDone: false // 默認(rèn)為false
});
WorkerLists = Ember.Object.extend({
// 定義一個(gè)Task對(duì)象數(shù)組
lists: [
Task.create({ isDone: false }),
Task.create({ isDone: true }),
Task.create(),
Task.create({ isDone: true }),
Task.create({ isDone: true }),
Task.create({ isDone: true }),
Task.create({ isDone: false }),
Task.create({ isDone: true })
],
remaining: Ember.computed('lists.@each.isDone', function() {
var lists = this.get('lists');
// 先查詢(xún)屬性isDone值為false的對(duì)象,再返回其數(shù)量
return lists.filterBy('isDone', false).get('length');
})
});
// 如下代碼使用到的API請(qǐng)查看:http://emberjs.com/api/classes/Ember.MutableArray.html
var wl = WorkerLists.create();
// 所有isDone屬性值未做任何修改
console.log('1,>> Not complete lenght is ' + wl.get('remaining')); // output 3
var lists = wl.get('lists'); // 得到對(duì)象內(nèi)的數(shù)組
// ----- 演示第一種情況: 1. 在todos數(shù)組中任意一個(gè)對(duì)象的isDone屬性值發(fā)生變化的時(shí)候;
// 修改數(shù)組一個(gè)元素的isDone的 值
var item1 = lists.objectAt(3); // 得到第4個(gè)元素 objectAt()方法是Ember為我們提供的
// console.log('item1 = ' + item1);
item1.set('isDone', false);
console.log('2,>> Not complete lenght is ' + wl.get('remaining')); // output 4
// --------- 2. 往todos數(shù)組新增元素的時(shí)候;
lists.pushObject(Task.create({ isDone: false })); //新增一個(gè)isDone為false的對(duì)象
console.log('3,>> Not complete lenght is ' + wl.get('remaining')); // output 5
// --------- 3. 從todos數(shù)組刪除元素的時(shí)候;
lists.removeObject(item1); // 刪除了一個(gè)元素
console.log('4,>> Not complete lenght is ' + wl.get('remaining')); // output 4
// --------- 4. 在控制器中todos數(shù)組被改變?yōu)槠渌臄?shù)組的時(shí)候;
// 創(chuàng)建一個(gè)Controller
TodosController = Ember.Controller.extend({
// 在控制器內(nèi)定義另外一個(gè)Task對(duì)象數(shù)組
todosInController: [
Task.create({ isDone: false }),
Task.create({ isDone: true })
],
// 使用鍵”@each.isDone“遍歷得到的filterBy()方法過(guò)濾后的對(duì)象的isDone屬性
remaining: function() {
// remaining()方法返回的是控制器內(nèi)的數(shù)組
return this.get('todosInController').filterBy('isDone', false).get('length');
}.property('@each.isDone') // 指定遍歷的屬性
});
todosController = TodosController.create();
var count = todosController.get('remaining');
console.log('5,>> Not complete lenght is ' + count); // output 1
上述的情況中,我們對(duì)數(shù)組對(duì)象的是關(guān)注點(diǎn)是在對(duì)象的屬性上,但是實(shí)際中往往很多情況我們并不關(guān)系對(duì)象內(nèi)的屬性是否變化了,而是把數(shù)組元素作為一個(gè)整體對(duì)象處理(比如數(shù)組元素個(gè)數(shù)的變化)。相比上述的代碼下面的代碼檢測(cè)的是數(shù)組對(duì)象元素的變化,而不是對(duì)象的isDone
屬性的變化。在這種情況你可以看看下面例子,在例子中使用鍵[]
代替鍵@each
。從鍵的變化也可以看出他們的不同之處。
Task = Ember.Object.extend({
isDone: false, // 默認(rèn)為false
name: 'taskName',
// 為了顯示結(jié)果方便,重寫(xiě)toString()方法
toString: function() {
return '[name = '+this.get('name')+', isDone = '+this.get('isDone')+']';
}
});
WorkerLists = Ember.Object.extend({
// 定義一個(gè)Task對(duì)象數(shù)組
lists: [
Task.create({ isDone: false, name: 'ibeginner.sinaapp.com' }),
Task.create({ isDone: true, name: 'i2cao.xyz' }),
Task.create(),
Task.create({ isDone: true, name: 'ubuntuvim' }),
Task.create({ isDone: true , name: '1527254027@qq.com'}),
Task.create({ isDone: true })
],
index: null,
indexOfSelectedTodo: Ember.computed('index', 'lists.[]', function() {
return this.get('lists').objectAt(this.get('index'));
})
});
var wl = WorkerLists.create();
// 所有isDone屬性值未做任何修改
var index = 1;
wl.set('index', index);
console.log('Get '+wl.get('indexOfSelectedTodo').toString()+' by index ' + index);
Ember.computed
這個(gè)組件中有很多使用鍵[]
實(shí)現(xiàn)的方法。當(dāng)你想創(chuàng)建一個(gè)計(jì)算屬性是數(shù)組的時(shí)候特別適用。你可以使用Ember.computed.map
來(lái)構(gòu)建你的計(jì)算屬性。
const Hamster = Ember.Object.extend({
chores: null,
excitingChores: Ember.computed('chores.[]', function() { //告訴Ember chores是一個(gè)數(shù)組
return this.get('chores').map(function(chore, index) {
//return `${index} --> ${chore.toUpperCase()}`; // 可以使用${}表達(dá)式,并且在表達(dá)式內(nèi)可以直接調(diào)用js方法
return `${chore}`; //返回元素值
});
})
});
// 為數(shù)組賦值
const hamster = Hamster.create({
// 名字chores要與類(lèi)Hamster定義指定數(shù)組的名字一致
chores: ['First Value', 'write more unit tests']
});
console.log(hamster.get('excitingChores'));
hamster.get('chores').pushObject("Add item test"); //add an item to chores array
console.log(hamster.get('excitingChores'));
Ember
還提供了另外一種方式去定義數(shù)組類(lèi)型的計(jì)算屬性。
const Hamster = Ember.Object.extend({
chores: null,
excitingChores: Ember.computed('chores.[]', function() {
return this.get('chores').map(function(chore, index) {
//return `${index} --> ${chore.toUpperCase()}`; // 可以使用${}表達(dá)式,并且在表達(dá)式內(nèi)可以直接調(diào)用js方法
return `${chore}`; //返回元素值
});
})
});
// 為數(shù)組賦值
const hamster = Hamster.create({
// 名字chores要與類(lèi)Hamster定義指定數(shù)組的名字一致
chores: ['First Value', 'write more unit tests']
});
console.log(hamster.get('excitingChores'));
hamster.get('chores').pushObject("Add item test"); //add an item to chores array
console.log(hamster.get('excitingChores'));
<br>
博文完整代碼放在Github(博文經(jīng)過(guò)多次修改,博文上的代碼與github代碼可能又出入,不過(guò)影響不大?。?,如果你覺(jué)得博文對(duì)你有點(diǎn)用在github項(xiàng)目上給我個(gè)star
吧。您的肯定對(duì)我來(lái)說(shuō)是最大的動(dòng)力??!
更多建議: