EmberJs之数组绑定@each&[]
写在前面
好长时间没有写博客了,昨天花了些时间又整理了下之前发布过的《Ember.js之computed Property》文章,并创建了一个测试代码库,花了些时间,希望能使用测试代码的方式,来演示如何使用Ember.js同时能避免升级Ember版本后,一些功能上的变化所带来的隐含Bug。
如果大家对Ember.js有兴趣想一起研究的话,欢迎大家一起维护测试代码库 :)
本文主要是针对Ember.Array中的[]和@each,数组方法进行详细分析。
文章索引
一、如何使用[] & @each
Ember中二者均可用于计算属性的绑定,使用十分方便,可以像如下方式定义依赖关系:
totalArea: Ember.computed('sizeArray.[]', function () {
return this.get('sizeArray').reduce(function (prev, cur) {
return prev + Ember.get(cur, 'height') * Ember.get(cur, 'width');
}, 0);
}),
或者:
totalArea: Ember.computed(‘sizeArray.@each', function () {
return this.get('sizeArray').reduce(function (prev, cur) {
return prev + Ember.get(cur, 'height') * Ember.get(cur, 'width');
}, 0);
}),
这样就定义了一个依赖于数组sizeArray的计算属性,建立一个绑定关系,只要sizeArray发生变化,totalArea就会被重新计算,使用十分简单,只要在function前面罗列出依赖的属性即可。虽然使用简单,但是在使用上还是有些细节的,下一节将用测试代码来讲解使用上的细节。
注:Ember计算属性有多种写法,这里给出了Ember推荐写法,更多具体细节请参考文章《Ember.js之computed Property-1. What is CP》
二、Array.[] & Array.@each特性总结
(Ember v1.13.7)
1. Array.@each.property 特性
当CP属性依赖于.property('columns.@each.isLoaded')时:
- columns里面任何一个元素的isLoaded属性发生变化。
- columns增加元素或者删除子元素。
- columns数组本身被重新赋值。
- 不能依赖@each.owner.@each.name 。
test('computed property depend on @each.height', function (assert) {
var Size = Ember.Object.extend({height: 0, width: 0});
var rectangle = Ember.Object.extend({
totalArea: Ember.computed('sizeArray.@each.height', function () {
return this.get('sizeArray').reduce(function (prev, cur) {
return prev + Ember.get(cur, 'height') * Ember.get(cur, 'width');
}, 0);
}),
sizeArray: [
Size.create({height: 10, width: 10}),
Size.create({height: 10, width: 10})
]
}).create();
var sizeArray = rectangle.get('sizeArray');
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200");
sizeArray.pushObject(Size.create({height: 10, width: 10}));
assert.equal(rectangle.get('totalArea'), 300, "the total area should be 300 after added");
sizeArray.removeAt(0);
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200 after removed");
sizeArray[0].set('height', 20);
assert.equal(rectangle.get('totalArea'), 300, "the total area should be 300 after 'height' changed");
sizeArray[0].set('width', 20);
assert.equal(rectangle.get('totalArea'), 300, "the total area should not be changed after 'width' changed");
sizeArray.clear();
assert.equal(rectangle.get('totalArea'), 0, "the total area should be 0 after reset rectangle.sizeArray");
});
2. Array.@each特性
当CP属性依赖于.property('columns.@each')时:
- columns增加或删除元素。
- columns自身被替换或重新赋值。
test('computed property depend on @each', function (assert) {
var Size = Ember.Object.extend({height: 0, width: 0});
var rectangle = Ember.Object.extend({
totalArea: Ember.computed('sizeArray.@each', function () {
return this.get('sizeArray').reduce(function (prev, cur) {
return prev + Ember.get(cur, 'height') * Ember.get(cur, 'width');
}, 0);
}),
sizeArray: [
Size.create({height: 10, width: 10}),
Size.create({height: 10, width: 10})
]
}).create();
var sizeArray = rectangle.get('sizeArray');
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200");
sizeArray.pushObject(Size.create({height: 10, width: 10}));
assert.equal(rectangle.get('totalArea'), 300, "the total area should be 300 after added");
sizeArray.removeAt(0);
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200 after removed");
sizeArray[0].set('height', 20);
assert.equal(rectangle.get('totalArea'), 200, "the total area should not be changed");
sizeArray.clear();
assert.equal(rectangle.get('totalArea'), 0, "the total area should be 0 after reset rectangle.sizeArray");
});
3. Array.[]特性
当CP属性依赖于.property('columns.[]')时:
- 与绑定.property(‘columns.@each') 行为相同。
test('computed property depend on []', function (assert) {
var Size = Ember.Object.extend({height: 0, width: 0});
var rectangle = Ember.Object.extend({
totalArea: Ember.computed('sizeArray.[]', function () {
return this.get('sizeArray').reduce(function (prev, cur) {
return prev + Ember.get(cur, 'height') * Ember.get(cur, 'width');
}, 0);
}),
sizeArray: [
Size.create({height: 10, width: 10}),
Size.create({height: 10, width: 10})
]
}).create();
var sizeArray = rectangle.get('sizeArray');
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200");
sizeArray.pushObject(Size.create({height: 10, width: 10}));
assert.equal(rectangle.get('totalArea'), 300, "the total area should be 300 after added");
sizeArray.removeAt(0);
assert.equal(rectangle.get('totalArea'), 200, "the total area should be 200 after removed");
sizeArray[0].set('height', 20);
assert.equal(rectangle.get('totalArea'), 200, "the total area should not be changed");
sizeArray.clear();
assert.equal(rectangle.get('totalArea'), 0, "the total area should be 0 after reset rectangle.sizeArray");
});
(Ember v2.0.0)
2015-08-17 除建议用[]代替@each,暂未发现其他变化。
[参考代码](https://github.com/emberjs/ember.js/blob/v2.0.0/packages/ember-metal/lib/computed.js#L224)
注: 更多关于计算属性问题,请参考文章《Ember.js之computed Property-3.CP重要原则》
三、源码分析Array.[] & Array.@each
Array.@each返回的是一个特殊类型,这个类型便于实现绑定。
'@each': computed(function() {
if (!this.__each) {
// ES6TODO: GRRRRR
var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy'];
this.__each = new EachProxy(this);
}
return this.__each;
})
[参考这里](https://github.com/emberjs/ember.js/blob/stable-1-13/packages/ember-runtime/lib/mixins/array.js#L516)
Array.[]继承自Ember.Enumerable.[]并且返回this。
'[]': computed({
get(key) {
return this;
},
set(key, value) {
this.replace(0, get(this, 'length'), value);
return this;
}
}),
[参考这里](https://github.com/emberjs/ember.js/blob/stable-1-13/packages/ember-runtime/lib/mixins/array.js#L164)
二者之间唯一的区别是Array.[]返回的是一对象自身(普通对象组成的数组), 而Array.@each返回的是EachProxy对象, 针对普通对象组成的数组而言,仅仅能检测到数组长度的变化和对象本身的变化,对数组内容发生变化则不得而知,而EachProxy对每一个元素增加observerListener监听器,当数组内容发生变化时,通知数组发生变更,实现了数组元素这一级别的监听。
var EachProxy = EmberObject.extend({
init(content) {
this._super(...arguments);
this._content = content;
content.addArrayObserver(this);
// in case someone is already observing some keys make sure they are
// added
forEach(watchedEvents(this), function(eventName) {
this.didAddListener(eventName);
}, this);
},
...
四、相关引用
[Ember-@each](http://emberjs.com/api/classes/Ember.Array.html#property__each)
[Emer-EachProxy](https://github.com/emberjs/ember.js/blob/stable-1-13/packages/ember-runtime/lib/system/each_proxy.js)
[Ember-study](https://github.com/Cuiyansong/ember-table-learnning)
EmberJs之数组绑定@each&[]的更多相关文章
- mvc数组绑定-jquery ajax
var list=[];//数组 list[0]=1001; list[1]=1002; list[1]=1003; var json_data = { selected: list}; $.ajax ...
- asp.net mvc int[] 和 string[] 自定义数组绑定
新建类,int[]数组模型绑定 using System; using System.Collections.Generic; using System.Linq; using System.Web; ...
- 给js创建的一个input数组绑定click事件
<html> <body> <input type="button" name="input[]" value="按钮1 ...
- 使用C# .NET 将结构数组绑定到 Windows 窗体的方法
本任务的内容 概要 要求 设计结构 向数组添加结构实例 将结构成员绑定到窗体控件 提供浏览数组的方式 分步示例 参考 概要 本文介绍如何向 Windows 窗体绑定结构数组. 该示例由一个 Win ...
- Spring MVC数组绑定
需求:商品批量删除,用户在页面选择多个商品,批量删除. 关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id // 批量删除 商品信息 @ ...
- Ng的数组绑定
tip:数据的定义需要在对应ts中进行,调用在html中 定义数组: ts中 public arr =["111","222","333"] ...
- Repeater绑定数组并显示其值
web开发中,尤其是对于数据展示,不得不说Repeater是一个万能的控件,而且使用也很方便. 在ASP.NET中将数组绑定到Repeater中请问如何在Repeater前台页面中显示该数组的值? s ...
- ASP.NET MVC数组模型绑定
在ASP.NET MVC中使用Razor语法可以在视图中方便地展示数组,如果要进行数组模型绑定,会遇到索引断裂问题,如下示例: <input type="text" name ...
- MVC数组模型绑定
ASP.NET MVC数组模型绑定 在ASP.NET MVC中使用Razor语法可以在视图中方便地展示数组,如果要进行数组模型绑定,会遇到索引断裂问题,如下示例: <input type=& ...
随机推荐
- Nginx密码验证 ngx_http_auth_basic_module模块
有时候我们需要限制某些目录只允许指定的用户才可以访问,我们可以给指定的目录添加一个用户限制. nginx给我们提供了ngx_http_auth_basic_module模块来实现这个功能. 模块ngx ...
- NC 查询公司下所分配的组织,并存放字符串数组中
private String[] querkFather() { String sql = "select pk_org from org_orgs start with pk_father ...
- odoo10 费用报销
odo10 对费用报销进行了改进,恢复了 8.0 及之前版本具有的 单个报销包含多个 明细内容的功能. 使用步骤大致如下: 根据管理需要设立 相应的科目和分析帐户 科目 分析帐户 建立费用目录 员工录 ...
- Co-saliency-Huazhu Fu
这里主要是fu老师的显著性检测分割的一些资料. 对应的主页为:http://hzfu.github.io/ 对应的一些codes:https://github.com/HzFu
- 在Xcode中使用Git进行源码版本控制
http://www.cocoachina.com/ios/20140524/8536.html 资讯 论坛 代码 工具 招聘 CVP 外快 博客new 登录| 注册 iOS开发 Swift Ap ...
- css3选择器总结
1.p[class^/$/*=td]所有p标签的前面带有td/后面带有td/所有带有td的类的三种样式. 2.div:first-child/last-child/nth-child()在父元素下的第 ...
- yaf框架学习笔记
1.yaf框架支持简单的试图引擎,并且支持用户自定义视图引擎,比如smarty. 2.Yaf_Request_Http::getQuery ,Yaf_Request_Http::getQuery ( ...
- MVC 3 IIS7.5 网站发布及IIS配置文件问题处理
1.环境配置 1) IIS7.5 2)VS2010 完整版 2.配置internet信息服务功能,直接上图,简洁明了. 3.打开VS2010 ,网站发布, 4.IIS网站设置 添加网站, 5-在浏览器 ...
- 替换CENTOS自带的yum源为网易163镜像源
首先确保你的系统是centos5或者centos6 先备份你系统自带的repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...
- JS-随机函数
// alert( Math.round(3.4) );// 0~1 : Math.round(Math.random());// 0~10// alert( Math.round(Math.rand ...