zoukankan      html  css  js  c++  java
  • Ember.js 入门指南——计算属性(compute properties)

    本系列文章全部从(http://ibeginner.sinaapp.com/)迁移过来,欢迎访问原网站。


    1,简单的计算属性

        简单地来说,计算属性就是将函数声明为属性。其实就是就是在类扩展的时候为类定义的属性。

    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获取函数的返回值。


    2,计算属性链

        在Ember程序中,计算属性还能调用另外一个计算属性,形成计算属性链,也可以用于扩展某个方法。在上一实例的基础上增加一个description()方法。

    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')得到的值也是更新后的值。


    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这个例子中有这样的一段代码。

    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数组新增元素的时候;

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

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Visual Basic 9.0 前沿播报·静态篇(二)对象初始化器和匿名类型
    Visual Basic 9.0 前沿播报内容概览
    Refactor! for VB —— VB2005的重构支持(一)
    我不知道该说什么,这里太先进了!
    Visual Basic 9.0 前沿播报·静态篇(一)局部变量类型推测和数组初始化器
    关于“就地颠倒句子里的词”面试题
    Visual Basic 9.0 前沿播报·静态篇(三)扩展方法
    《窝窝世界》视频20101025
    Silverlight 游戏开发小技巧:透明背景的Silverlight程序
    Silverlight 游戏开发小技巧:技能冷却效果2(Cooldown)2
  • 原文地址:https://www.cnblogs.com/ubuntuvim/p/4796590.html
Copyright © 2011-2022 走看看