标签:
In a nutshell, computed properties let you declare functions as properties. You create one by defining a computed property as a function, which Ember will automatically call when you ask for the property. You can then use it the same way you would any normal, static property.
App.Person = Ember.Object.extend({ // these will be supplied by `create` firstName: null, lastName: null, fullName: function() { return this.get(‘firstName‘) + ‘ ‘ + this.get(‘lastName‘); }.property(‘firstName‘, ‘lastName‘) }); var ironMan = App.Person.create({ firstName: "Tony", lastName: "Stark" }); ironMan.get(‘fullName‘); // "Tony Stark"
这里fullName是一个CP,依赖于firstName,lastName.
另:CP也可以这样写,建议如下写法,避免“禁用”function的property扩展带来的问题。
fullName: Ember.computed(‘firstName‘, ‘lastName‘, function() { return this.get(‘firstName‘) + ‘ ‘ + this.get(‘lastName‘); })
2.1 CP:Computed Property。
2.2 CP属性:上文例子中的‘fullName’。
2.3 CP所依赖的源属性:上文例子中的‘firstName’、‘lastName’。
2.4 CP的回调方法:上文例子中的function(){......}方法。
2.5 CP属性的Setter/Getter:
3.1 只有当获取或设置CP属性时,才可能会触发CP的回调方法,也就是说CP属性是属于‘懒加载’的方式(使用时加载的行为)。
3.2 当CP属性依赖于.property(‘person{name,age}‘)时,仅当person.name或person.age发生改变时改变,其余方式均不可以更新CP属性。
3.3 当CP属性依赖于.property(‘columns.@each.isLoaded‘)时, 以下四种情况会发生变化:
@each
only works one level deep. You cannot use nested forms like todos.@each.owner.name
or todos.@each.owner.@each.name
.3.4 当CP属性依赖于.property(‘columns.@each‘)时,其行为会发生如下变化:
3.5 当CP属性依赖于.property(‘columns.[]‘)时,其行为会发生如下变化:
与3.4 绑定.property(‘columns.@each‘) 行为相同。
3.6 当通过set方法设置CP属性时,然后调用get方法获取CP属性,则不调用CP回调,set时值被缓存。
3.7 对象在继承CP属性时,保持CP属性的独立性、互不干扰,并且重写后会改写CP依赖关系,变更依赖源。
3.8 当存在两个互相依赖的CP属性时,仅仅发生三次属性变更。
3.9 不要将CP的依赖属性附着在另一个CP属性上。
3.10 当CP属性依赖于对象列表时,例如.property(‘a.b.c.d‘)上时,节点上任意对象发生变化时,均会重新计算属性(当调用CP属性时)。
总原则:CP依赖的属性发生改变后,当调用CP值时,会触发宏的重新计算(触发回调function)。
Ember.computed.empty: empty(属性名)返回bool
Ember.computed.not: not(属性名)返回bool
Ember.computed.alias:alias(属性名),双向绑定, alias不要依赖于一个CP.
Ember.computed.defaultTo: 如果CP属性为null,则读取依赖属性值一次
Ember.computed.match(属性名, 匹配字符串)
Ember.computed.gt(属性名,数字),大于返回bool
Ember.computed.gte(属性名,数字),大于或等于bool
Ember.computed.and(属性名,属性名), 并集
Ember.computed.or(属性名, 属性名), 交集
Ember.computed.collect( 数组 ) ,匹配所有项,没有相则为null
Ember.computed.oneWay(属性名) ,单方向从源到PC属性,并且仅执行一次。
Ember.computed.readOnly(属性名) ,CP属性不允许被设置,但CP所依赖的源属性更新CP值。
更多宏定义请参考这里:http://emberjs.com/api/classes/Ember.computed.html#method_alias
5.1 在我们使用的对象上,希望使用一个属性值监听一个或多个属性的变更,或者CP属性强依赖于某些属性,而且还能缓存CP属性值,减少性能损耗。(CP特性请参考3.1)
5.2 CP可以依赖在一个对象的多个属性上, 特别是绑定在集合元素上甚至监听集合元素内部某一属性,但层次有限制。例如.property(‘person{name,age}‘)或.property(‘pencilBox.[]‘, penBox.@each.color‘, penBox.@each)。(CP特性请参考3.2、3.3、3.4)
5.3 Ember.computed.alias作用于两个强关联对象的双向绑定,并提供缓存机制。
5.4 通过CP来组合属性,CP属性回调中不能有边界效应等循环、异步方法。
var computedCount = 0; module(‘CP test‘, { beforeEach: function () { computedCount = 0; }, afterEach: function () { } }); test(‘Should change dependency property value when CP property changed and binding style is Ember.computed.alias‘, function(assert){ var Person = Ember.Object.extend({ name: ‘Alex Matchneer‘, nomen: Ember.computed.alias(‘name‘) }); var alex = Person.create(); alex.get(‘nomen‘); // ‘Alex Matchneer‘ alex.get(‘name‘); // ‘Alex Matchneer‘ alex.set(‘nomen‘, ‘@machty‘); assert.ok(alex.get(‘name‘), ‘@machty‘); }); test(‘Should change CP property when dependency property changed changed and binding style is Ember.computed.alias‘, function(assert){ var Person = Ember.Object.extend({ name: ‘Alex Matchneer‘, nomen: Ember.computed.alias(‘name‘) }); var alex = Person.create(); alex.get(‘nomen‘); // ‘Alex Matchneer‘ alex.get(‘name‘); // ‘Alex Matchneer‘ alex.set(‘name‘, ‘@machty‘); assert.ok(alex.get(‘nomen‘), ‘@machty‘); }); test(‘Should compute fullName when dependency property of columns inner item changed and binding style is columns.@each.isDone‘, function(assert) { var Person = Ember.Object.extend({ columns: [ Ember.Object.create({ isDone: true, isLoading: false }), Ember.Object.create({ isDone: false, isLoading: false }), Ember.Object.create({ isDone: true , isLoading: false }) ], fullName: Ember.computed(function(key, value) { computedCount++; return this.columns.length; }).property(‘columns.@each.isDone‘) }); var client = Person.create(); client.get(‘fullName‘); assert.ok(computedCount === 1); client.get(‘columns‘).objectAt(1).set(‘isLoading‘, true); client.get(‘fullName‘); assert.ok(computedCount === 1); client.get(‘columns‘).objectAt(1).set(‘isDone‘, true); client.get(‘fullName‘); assert.ok(computedCount === 2); client.get(‘columns‘).removeAt(1); client.get(‘fullName‘); assert.ok(computedCount === 3); client.get(‘columns‘).addObject(Ember.Object.create({ isDone: true, isLoading: false })); client.get(‘fullName‘); assert.ok(computedCount === 4); client.set(‘columns‘,[]); client.get(‘fullName‘); assert.ok(computedCount === 5); }); test(‘Should compute fullName when dependency property of columns inner item changed and binding style is columns.@each‘, function(assert) { var Person = Ember.Object.extend({ columns: [ Ember.Object.create({ isDone: true, isLoading: false }), Ember.Object.create({ isDone: false, isLoading: false }), Ember.Object.create({ isDone: true , isLoading: false }) ], fullName: Ember.computed(function(key, value) { computedCount++; return this.columns.length; }).property(‘columns.@each‘) }); var client = Person.create(); client.get(‘fullName‘); console.log( "After get fullName, computedCount should be equal "+ computedCount); client.get(‘columns‘).objectAt(1).set(‘isLoading‘, true); client.get(‘fullName‘); console.log("After set isLoading to true, computedCount should be equal "+ computedCount); client.get(‘columns‘).objectAt(1).set(‘isDone‘, true); client.get(‘fullName‘); console.log( "After set isDone to true, computedCount should be equal "+ computedCount); client.get(‘columns‘).removeAt(1); client.get(‘fullName‘); console.log( "After remove column item, computedCount should be equal "+ computedCount); client.get(‘columns‘).addObject(Ember.Object.create({ isDone: true, isLoading: false })); client.get(‘fullName‘); console.log( "After add new object, computedCount should be equal "+ computedCount); client.set(‘columns‘,[]); client.get(‘fullName‘); console.log( "After replace itself, computedCount should be equal "+ computedCount); assert.ok(true); }); test(‘Should compute fullName when dependency property of columns inner item changed and binding style is columns.[]‘, function(assert) { var Person = Ember.Object.extend({ columns: [ Ember.Object.create({ isDone: true, isLoading: false }), Ember.Object.create({ isDone: false, isLoading: false }), Ember.Object.create({ isDone: true , isLoading: false }) ], fullName: Ember.computed(function(key, value) { computedCount++; return this.columns.length; }).property(‘columns.[]‘) }); var client = Person.create(); client.get(‘fullName‘); console.log( "After get fullName, computedCount should be equal "+ computedCount); client.get(‘columns‘).objectAt(1).set(‘isLoading‘, true); client.get(‘fullName‘); console.log("After set isLoading to true, computedCount should be equal "+ computedCount); client.get(‘columns‘).objectAt(1).set(‘isDone‘, true); client.get(‘fullName‘); console.log( "After set isDone to true, computedCount should be equal "+ computedCount); client.get(‘columns‘).removeAt(1); client.get(‘fullName‘); console.log( "After remove column item, computedCount should be equal "+ computedCount); client.get(‘columns‘).addObject(Ember.Object.create({ isDone: true, isLoading: false })); client.get(‘fullName‘); console.log( "After add new object, computedCount should be equal "+ computedCount); client.set(‘columns‘,[]); client.get(‘fullName‘); console.log( "After replace itself, computedCount should be equal "+ computedCount); assert.ok(true); });
标签:
原文地址:http://www.cnblogs.com/cuiyansong/p/4550150.html