Emberjs学习

断断续续看了3周,还是一头雾水,文档不是很友好,这个框架,太多潜规则,学习曲线太大了。
简单记录一些学习笔记。

1. Ember适用于单页面网站的构建。依赖 jQuery 和 Handlebars 2个库。

2. 基于路由的控制有2种方式:带hash的url和支持history API的url。
前者要求IE8+,后者要求IE10+。有关浏览器支持部分,请参阅:http://caniuse.com/#search=history,http://caniuse.com/#search=hashchange
或许是因为浏览器兼容问题——广度和成熟度,Ember默认使用带hash的url路由控制。

3. Ember使用了ES5的对于Object的属性访问控制,从而要求IE9+.有关浏览器支持情况,请参阅:http://kangax.github.io/compat-table/es5/#Object.defineProperty

4. Ember是面向对象的,有类、实例、继承的概念。对于属性的读写,会触发相应的change事件,从而通知到观察者,做出相应的动作。
例如:

//定义一个类:
var Point = Ember.Object.extend({
x: null,
y: null,
z: null,
logX: function(){
console.log(this.get('x'));
},
logY: function(){
console.log(this.get('y'));
},
logZ: function(){
console.log(this.get('z'));
}
});
//创建一个对象
var point = Point.create({
x: 3,
y: 5,
z: 7
});
point.logX();// 3

//对象继承
var Vector = Point.extend({
add: function(vector){

var x = this.get('x') + vector.get('x');
var y = this.get('y') + vector.get('y');
var z = this.get('z') + vector.get('z');

this.set('x', x);
this.set('y', y);
this.set('z', z);

}
});
//实例A
var vectorA = Vector.create({
x: 3,
y: 5,
z: 7
});
//实例B
var vectorB = Vector.create({
x: 1,
y: 2,
z: 3
});
//应用新方法
vectorA.add(vectorB);

vectorA.logX(); //4


4.1 通常在类定义的时候,就已经确定好属性和方法了。如果要修改意见定义的类,则需要使用 reopen (类函数)/reopenClass(静态函数)。

var Book = Em.Object.extend();
Book.reopen({
id: null,
title: null,
purchase: function(){
console.log('sold');
}
});

//类的静态方法
Book.reopenClass({
getById: function(id){
return Book.create({
id: '456',
title: 'Harry Potter'
});
}
});

Book.create({
id: 456,
title: 'Harry Potter'
});

var book = Book.getById(456);

book.purchase();


5. Ember是基于MVC来设计的,M/V/C都有相应基础的类,还有一个Route,它控制了页面的流转,可以说是程序各个模块的入口。
而我们要做的,继承这些基础的类,编写相应模块的M/V/C/R.

一个route 的典型工作,有如下面代码所示:

App.PostRoute = Ember.Route.extend({
//1. 根据url参数,获取model数据
model: function(params){
return Ember.$.getJSON('/posts/'+params.post_id);
},

//2. 把model 赋值给对应 controller 的 model属性。这个函数是默认的。
setupController: function(controller, model){
// [3]. 可以在这里自定义
controller.set('model', model);
}
});


Ember对MVC/R都遵循着同一套的命名规则,并且在用户没有显示定义的时候,它会在后台为用户生成。例如:
一个Ember应用程序Application,默认就会有一个 ApplicationController/ApplicationRoute/application/ApplicationView,route为 /

例如,我们有下面的路由定义:

App.Router.map(function(){
this.resource('users', function(){
this.resource('user', { path:'/:user_id' }, function(){
this.route('edit');
});
this.route('create');
});

this.route('about');
}

最终得到的MVC对象将会有:
[table]
|URL |Route Name |Controller |Route |Template|
|N/A |N/A |ApplicationController |ApplicationRoute |application|
|/ |index |IndexController |IndexRoute |index|
|N/A |users |UsersController |UsersRoute |users|
|/users |users.index |UsersIndexController |UsersIndexRoute |users/index
|N/A |user |UserController |UserRoute |user|
|/users/:user_id |user.index |UserIndexController |UserIndexRoute |user/index|
|/users/:user_id/edit |user.edit |UserEditController |UserEditRoute |user/edit|
|/users/create |users.create |UsersCreateController |UsersCreateRoute | users/create|
[/table]
5.1 路由定义: route VS resource
相同:两者都可以定义路由;
不同:resource更像是一个盒子,里面可以内嵌route,通常用于划分模块;resource用于区分模块,还可以缩短它里面route的MVC命名,
不必从根路径开始,而是以当前resource做起点即可。譬如,在上面route定义中:

UserEditRoute instead of UsersUserEditRoute;
UserEditControler instead of UsersUserEditController;
UserEditView instead of UsersUserEditView;
for templates, user/edit instead of users/user/edit.

route则已经是最小的路由定义了,一般是指向模块内一个分支/动作。

5.2 如果定义resource时候,没有同时提供函数,则路径 resource.index 对应的route 不会被创建。
如此一来,/resource的访问,将直接使用 ResourceRoute, ResourceController, and resource template.

5.3 路由跳转 transitionTo VS transitionToRoute
// from a route
this.transitionTo('your.route');

// from a controller
this.transitionToRoute('your.route');


6. Controller 扮演 View与Route之间的桥梁,用它封装Model,并定义了一系列和服务器通讯的功能。

6.1 Controller 在Ember中都是单例模式,访问同一路径,不会创建新的实例。
6.2 ArrayController VS ObjectController VS Controller

ArrayController 继承自 Ember.ArrayProxy,适用于model为数组对象,从而可以内置并利用数组的排序等功能;
ObjectController 继承自 Ember.ObjectProxy,适用于model为单个对象情况。
Controller 继承自 Ember.Object。

显然,如果直接Controller它创建的实例,view获得的数据,只能从该controller获取,无法向上寻找到route。
而ArrayController、ObjectController都继承自Proxy,有了“代理”功能,可以向上寻找route,从中获取model。

示例:

App = Ember.Application.create({LOG_ACTIVE_GENERATION:true});

App.IndexRoute = Ember.Route.extend({
model: function(){
var author = Ember.Object.create({name: 'Cory'});
return author;
}
//setupController默认就是把 controller与route 的model进行关联。
,setupController: function(controller, model){
// oops, forgot to do
// controller.set('model', model);
controller.set('isFancy', true);
}
});

App.IndexController = Ember.ObjectController.extend({ //允许向上访问route的属性。
//App.IndexController = Ember.Controller.extend({ //只有这里定义的属性,能够被view访问到。
isFancy: false,
greeting: function(){
if (this.get('isFancy')) {
return 'Salutations';
} else {
return 'Hello';
}
}.property('isFancy')
});

Ember.TEMPLATES.index = Ember.Handlebars.compile( "{{greeting}}, {{name}}<br>Is Fancy? {{input type='checkbox' checked=isFancy}}");

不同点二:

var post = App.Post.create({
title: 'JavaScript prototypes.',
body: 'This post will discuss JavaScript prototypes.'
});

// ObjectController 内置对属性的访问
var postController = Ember.ObjectController.create();
postController.set('model', post);
postController.get('title'); // JavaScript prototypes.


//用户需要手动指定属性
var postController = Ember.Controller.create();
postController.set('model', post);
postController.get('title'); // undefined
postController.get('model.title'); // JavaScript prototypes.

var controller = Ember.ArrayController.create({
model: [1, 2, 3]
});

// 默认就是model的length属性
controller.get('length'); // 3

//Array相关的方法,也都可以直接调用
controller.contains(1); //true

//更多方法: addObject() / addObjects() / every(callback) / filter(object) / ...


7. Ember 通常的事件流转顺序是:
a. template element(e.g: click);
b. 查找对应Controller的action定义,如果不存在,则c;
c. 查找对应Routed的action定义,如果不存在,则d;
d. 查找上一级的Route中的action定义,如果不存在,则重复 d,直到AppcationRoute截止。


8. Component:
8.1 和view有些相像,事实上,它正式View的一个子类。它通过预定义的接口与其它component/View通信。
8.2 每一个Component的模板命名都需要以 "components/" 开头。例如:
<script type="text/x-handlebars" id="components/blog-post">
<h1>Blog Post</h1>
<p>Lorem ipsum dolor sit amet.</p>
</script>

Component Name Component Class
blog-post App.BlogPostComponent
audio-player-controls App.AudioPlayerControlsComponent
8.3 两种定义方法:
a. 把事件绑在事件函数的上面
upload: function(){
...
}.on('click')
b. 用key-value的形式:
click: function(){
//do updoad
}
8.4 component 如何与application的其它功能做交互?
可以通过定义事件,然后利用ember的事件发送,实现参数的传递、交互。

示例:
//1. 定义一个添加到购物车的按钮控件
App.CheckoutButtonComponent = Ember.Component.extend({
tagName: 'button',
template: Ember.Handlebars.compile('add to cart'),
click: function(){

//发送事件及其参数
this.sendAction('action', this.get('product'));
}
});

{{! 2. 购物车模板}}
<ul>
{{#each products}}
<li>
{{name}}
{{price}}
{{checkout-button product=this action='addToCart'}} {{! 把数据传递给component }}
</li>
</ul>

//3. 购物的controller,定义事件
App.CartController = Ember.ArrayController.extend({
actions: {
addToCart: function(product){
this.pushObjects(product);
}
}
});

注意:Component仅能向父级发送事件。
如果 ComponentA 里面嵌套了 ComponentB,那么ComponentB 中sendAction只能到达 ComponentA,
如果需要把该事件冒泡到 Controller 那一层,你需要在 ComponentA 里面接收该事件,并做接力,向上发送。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值