×

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会自动调用这个函数。计算属性最大的特点就是能自动检测变化,及时更新数据。

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

计算属性链

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

重写计算属性的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'));

运行结果

计算属性值的统计

我们经常会遇到这种情况:某个计算属性值是依赖某个数组或者其他对象的,比如在Embertodos这个例子中有这样的一段代码。

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(嵌套)这两种方式都是不允许的。

在如下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

代码演示的结果

上述的情况中,我们对数组对象的是关注点是在对象的属性上,但是实际中往往很多情况我们并不关系对象内的属性是否变化了,而是把数组元素作为一个整体对象处理(比如数组元素个数的变化)。相比上述的代码下面的代码检测的是数组对象元素的变化,而不是对象的isDone属性的变化。在这种情况你可以看看下面例子,在例子中使用键[]代替键@each。从键的变化也可以看出他们的不同之处。

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

代码演示的结果

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

分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)