Ember.js 入門指南——計算屬性(compute properties)

本系列文章所有從(http://ibeginner.sinaapp.com/)遷移過來,歡迎訪問原網站。


1,簡單的計算屬性

    簡單地來講,計算屬性就是將函數聲明爲屬性。其實就是就是在類擴展的時候爲類定義的屬性。html

Person = Ember.Object.extend({
    firstName: null,
    lastName: null,
   
    //  fullName 就是一個計算屬性
    fullName: Ember.computed('firstName', 'lastName', function() {
        return this.get('firstName') + ", " + this.get('lastName');
    })
});
 
//  實例化同時傳入參數
var piter = Person.create({
    firstName: 'chen',
    lastName: 'ubuntuvim'
});
console.log(piter.get('fullName'));  // output >>   chen, ubuntuvim

    計算屬性其實就是一個函數,若是你接觸過就jQuery、Extjs相信你回很是熟悉,在這兩個框架中函數就是這麼定義的。只不過在Ember中,把這種函數當作屬性來處理,而且能夠經過get獲取函數的返回值。ubuntu


2,計算屬性鏈

    在Ember程序中,計算屬性還能調用另一個計算屬性,造成計算屬性鏈,也能夠用於擴展某個方法。在上一實例的基礎上增長一個description()方法。vim

Person = Ember.Object.extend({
    firstName: null,
    lastName: null,
    age: null,
    county: null,
   
    //  fullName 就是一個計算屬性
    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');
    })
});
 
//  實例化同時傳入參數
var piter = Person.create({
    firstName: 'chen',
    lastName: 'ubuntuvim',
    age: 25,
    county: 'china'
});
console.log(piter.get('description'));  // output >>   chen, ubuntuvim

    當用戶使用set方法改變firstName的值,而後再調用get('description')獲得的值也是更新後的值。api


3,重寫計算屬性的get、set方法

注意要把從新的屬性做爲參數傳入computed方法,要區別計算屬性的定義方法,定義的時候computed方法的最後一個參數是一個function,而重寫的時候最後一個參數是一個hash。數組

//    重寫計算屬性的get、set方法
Person = Ember.Object.extend({
    firstName: null,
    lastName: null,
   
    //  重寫計算屬性fullName的get、set方法
    fullName: Ember.computed('firstName', 'lastName', {
        get(key) {
            return this.get('firstName') + "," + this.get('lastName');
        },
        set(key, value) {
            //  這個官方文檔使用的代碼,可是我運行的時候出現 Uncaught SyntaxError: Unexpected token [  這個錯誤,不知道是不是缺乏某個文件,後續會補上;
//            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);
           
        }
    }),
//    對於普通的屬性沒法重寫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'));

blob.png

4,計算屬性值的統計

咱們常常會遇到這種狀況:某個計算屬性值是依賴某個數組或者其餘對象的,好比在Ember JS 的todos這個例子中有這樣的一段代碼。app

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');
  })
});

    計算屬性remaining的值就是依賴數組todos。在這裏還有個知識點:在上述代碼computed()方法裏有一個todos.@each.isDone這樣的鍵,裏面包含了一個特別的鍵「@each」(後面還會看到更特別的鍵「[]」)。須要注意的是這種鍵不能嵌套而且是隻能獲取一個層次的屬性。好比todos.@each.foo.name(獲取多層次屬性,這裏是先獲得foo再獲取name)或者todos.@each.owner.@each.name(嵌套)這兩種方式都是不容許的。todos.@each.foo.name框架

       在以下4種狀況Ember會自動更新綁定的計算屬性值:函數

1.        todos數組中任意一個對象的isDone屬性值發生變化的時候;網站

2.        todos數組新增元素的時候;this

3.        todos數組刪除元素的時候;

4.        在控制器中todos數組被改變爲其餘的數組的時候;

好比下面代碼演示的結果;

Task = Ember.Object.extend({
  isDone: false  //  默認爲false
});
 
WorkerLists = Ember.Object.extend({
  //  定義一個Task對象數組
  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');
    //  查詢屬性isDone值爲false的對象,並返回其數量
    return lists.filterBy('isDone', false).get('length');
  })
});
 
// 以下代碼使用到的API請查看: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');  //  獲得對象內的數組
 
// -----  演示第一種狀況: 1. 在todos數組中任意一個對象的isDone屬性值發生變化的時候;
//  修改數組一個元素的isDone的 值
var item1 = lists.objectAt(3);  //  獲得第4個元素 objectAt()方法是Ember爲咱們提供的
// console.log('item1 = ' + item1);
item1.set('isDone', false);
console.log('2,>> Not complete lenght is ' + wl.get('remaining'));  //  output 4
 
//  --------- 2.  往todos數組新增元素的時候;
lists.pushObject(Task.create({ isDone: false }));  //新增一個isDone爲false的對象
console.log('3,>> Not complete lenght is ' + wl.get('remaining'));  //  output 5
 
//  --------- 3.  從todos數組刪除元素的時候;
lists.removeObject(item1);  // 刪除了一個元素
console.log('4,>> Not complete lenght is ' + wl.get('remaining'));  //  output 4
 
//  --------- 4.  在控制器中todos數組被改變爲其餘的數組的時候;
//  建立一個Controller
TodosController = Ember.Controller.extend({
  // 在控制器內定義另一個Task對象數組
  todosInController: [
    Task.create({ isDone: false }),
    Task.create({ isDone: true })
  ],
  //  使用鍵」@each.isDone「遍歷獲得的filterBy()方法過濾後的對象的isDone屬性
  remaining: function() {
    //  remaining()方法返回的是控制器內的數組
    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

blob.png

    上述的狀況中,咱們對數組對象的是關注點是在對象的屬性上,可是實際中每每不少狀況咱們並不關係對象內的屬性是否變化了,而是把數組元素做爲一個總體對象處理,相比上述的代碼咱們只關心數組對象元素的變化,而不是對象的isDone屬性的變化。在這種狀況你能夠看看下面例子,在例子中使用鍵「[]」代替鍵「@each.foo」。從鍵的變化也能夠看出他們的不一樣之處。

Task = Ember.Object.extend({
  isDone: false,  //  默認爲false
  name: 'taskName',
  //  爲了顯示結果方便,重寫toString()方法
  toString: function() {
    return '[name = '+this.get('name')+', isDone = '+this.get('isDone')+']';
  }
});
 
WorkerLists = Ember.Object.extend({
  //  定義一個Task對象數組
  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);

blob.png

    Ember.computed這個組件中有不少使用鍵「[]」實現的方法。當你想建立一個計算屬性是數組的時候特別適用。你可使用Ember.computed.map來構建你的計算屬性。

const Hamster = Ember.Object.extend({
  chores: null,
  excitingChores: Ember.computed('chores.[]', function() { //告訴Ember chores是一個數組
    return this.get('chores').map(function(chore, index) {
      //return `${index} --> ${chore.toUpperCase()}`;  //  可使用${}表達式,而且在表達式內能夠直接調用js方法
      return `${chore}`;  //返回元素值
    });
  })
});
 
//  爲數組賦值
const hamster = Hamster.create({
  //  名字chores要與類Hamster定義指定數組的名字一致
  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還提供了另一種方式去定義數組類型的計算屬性。

const Hamster = Ember.Object.extend({
  chores: null,
  excitingChores: Ember.computed('chores.[]', function() {
    return this.get('chores').map(function(chore, index) {
      //return `${index} --> ${chore.toUpperCase()}`;  //  可使用${}表達式,而且在表達式內能夠直接調用js方法
      return `${chore}`;  //返回元素值
    });
  })
});
 
//  爲數組賦值
const hamster = Hamster.create({
  //  名字chores要與類Hamster定義指定數組的名字一致
  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'));
相關文章
相關標籤/搜索