ember语法
# 概述
Ember.js是一个开源的JavaScript客户端框架,用于开发Web应用程序并使用MVC(模型 - 视图 - 控制器)架构模式。在Ember.js中,路由用作模型,handlebar模板作为视图,控制器处理模型中的数据。
# 历史
Ember.js的原始名称是SproutCore MVC框架。它由Yehuda Katz开发,最初于2011年12月发布。
# 特征
- Ember.js用于创建可重用和可维护的JavaScript Web应用程序。
- Ember.js视图通过使用Handlebars模板创建,并且易于开发前端设计。
- 它在声明路由资源期间自动确定路由和控制器。
- Ember.js消除了样板(必须包含在各个地方的代码段,没有任何改动),并提供标准的应用程序架构。
- Ember.js具有HTML和CSS作为开发模型的核心。
- 路由是Ember.js的核心功能,用于管理URL。
- 它具有广泛的视图类型支持。
- Ember.js使用模板来帮助自动更新模型,如果应用程序的内容更改。
# 应用
# 架构
下图显示了Ember.js的架构,它说明了路由,控制器,视图,模板和模型之间的交互。
Ember.js的架构有以下内容:
- 模型
- 视图
- 模板
- 控制器
- 路由
模型
模型和路由相关联,因为模型通过作为参数传递到调用路由来实现路由。它操作存储在数据库中的数据。该模型是扩展Ember数据功能的简单类。Ember Data是一个与Ember.js紧密耦合的库,用于存储在数据库中的数据。
视图
创建视图有两个原因:
- 如果存在处理用户事件的复杂性。
- 您可以创建可重复使用的组件。
视图负责处理用户事件并更新DOM(文档对象模块)。将评估handlebar模板以创建视图。在模板评估期间,将添加子视图。它通过为最终用户提供丰富的UI,帮助保持应用程序系统的健壮性。
模板
模板是最终用户的强大的UI。您可以直接将模板嵌入到HTML标记中。Ember.js提供了Handlebar模板库来构建前端应用程序,就像普通HTML一样。它还支持正则表达式并动态更新表达式。
控制器
控制器管理模型的显示逻辑,并且还控制路线,模型和视图之间的操作。它从路由获取模型,并在视图,模型和模板之间建立连接。 Ember.js自动创建控制器。
路由
路由是应用程序对象的URL表示,并将其转换为嵌套模板。它从它们的模型钩子查询模型,以便在控制器和模板中可用。它在单例路由器对象中声明。
# 对象模型
面向对象的分析和设计技术被称为对象建模。在Ember.js中,所有对象都来自Ember.Object。
# 类和实例
类是一个模板或蓝色打印,具有变量和函数的集合,其中作为实例与该类的对象相关。
您可以使用Ember.Object的extend()方法创建新的Ember类,如下所示:
App.NameOfClass = Ember.Object.extend({
VariableName1:'values',
..
VariableNamen:'values',
FunctionName: function(thing)
{
//display logic
}
});
2
3
4
5
6
7
8
9
NameOfClass和FunctionName是类的名称和在类中定义的函数的名称。
让我们看看如何使用基类来扩展子类,如下所示:
App = Ember.Application.create();
App.Student = Ember.Object.extend({
disp: function() {
var roll = this.get('rollnum');
var name = this.get('name');
document.write("Roll num: "+roll+" Name: "+name);
}
});
App StudentInfo = App.Student.extend({
rollnum:"12",
name: "Jhon",
});
2
3
4
5
6
7
8
9
10
11
12
13
在上面的代码中,基类的名称是Student,StudentInfo是子类,它由基类扩展。disp是在基类中声明的函数的名称,显示学生信息。您可以使用_super()方法来立即引用父类方法。
# 计算属性
计算属性允许将函数声明为属性。Ember.js在需要时自动调用计算的属性,并在一个变量中组合一个或多个属性。
App = Ember.Application.create();
App.Car = Ember.Object.extend({
CarName: null,
CarModel: null,
fullDetails: function() {
return this.get('CarName') + ' ' + this.get('CarModel');
}.property('CarName', 'CarModel')
});
var car_obj = App.Car.create({
//initializing the values of Car variables
CarName: "Alto",
CarModel: "800",
});
//Displaying the Car information
document.write("Details of the car: <br>");
document.write(car_obj.get('fullDetails'));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在上述代码中, fullDetails 是调用 *property()*方法来呈现两个值(即CarName和CarModel)的计算属性。每当 fullDetails 被调用时,它返回 CarName 和 CarModel 。
# 计算属性的属性
- 替代调用 (opens new window) 它将一个或多个值传递给计算的属性,而不使用property()方法。
- 链接计算属性 (opens new window) 链接计算的属性用于与一个或多个预定义的计算属性进行聚合。
- 动态更新 (opens new window) 调用计算属性时动态更新。
- 设置计算属性 (opens new window) 使用 setter和getter 设置计算的属性。
# 对象模型替代调用
在替代调用中,可以将一个或多个值传递给计算的属性,而不使用property()方法。这是可能的,因为Ember.js扩展了函数原型。
ComputedPropertyName: Ember.computed('VarName1','VarName1','...','VarNamen', function(){
return VarName;
})
2
3
<script type="text/javascript">
App = Ember.Application.create();
App.Car = Ember.Object.extend({
CarName: null,
CarModel: null,
CarYear: null,
//defining the computed property function fullDetails
fullDetails: Ember.computed('CarName', 'CarModel','CarYear', function(){
return ' Car Name: '+this.get('CarName') + ' Car Model: ' + this.get('CarModel')+' Year: '+this.get('CarYear');
})
});
var car_obj = App.Car.create({
CarName: "Alto",
CarModel: "800",
CarYear: "2012",
});
//get the details of the 'fullDetails' computed property and display them
document.write("Full details of the Car:<br>"+car_obj.get('fullDetails'));
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 对象模型链接计算属性
链接计算属性用于与单个属性下的一个或多个预定义计算属性进行聚合。
App.ClassName = Ember.Object.extend({
NameOfComputedProperty1: function() {
return VariableName;
}.property('VariableNames','...','VariableNamesn'),
NameOfComputedProperty2: function() {
return VariableName;
}.property('NameOfComputedProperty1', 'VariableNames','...','VariableNamesn')
});
2
3
4
5
6
7
8
9
App = Ember.Application.create();
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
mobno: null,
//Defining the Person and Details computed property function
Person: function () {
return this.get("firstName") + " " + this.get("lastName");
}.property("firstName", "lastName"),
Details: function () {
return (
"Name: " +
this.get("Person") +
" Age: " +
this.get("age") +
" Mob No: " +
this.get("mobno")
);
}.property("Person", "age", "mbno"),
});
var emp = App.Person.create({
//initializing the values for variable
firstName: "Jhon",
lastName: "K",
age: 24,
mobno: "8792227920",
});
document.write("Details of employee: <br>");
document.write(emp.get("Details")); //displaying the values by get() method
// Details of employee:
// Name: Jhon K Age: 24 Mob No: 8792227920 输出
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 对象模型动态更新
Ember.js的set()方法有助于在调用计算属性时动态更新计算属性。
ClassName.set('VariableName', 'UpdatedValue');
App = Ember.Application.create();
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
mobno: null,
//defining the 'Details' as computed property fucntion
Person: function () {
return this.get("firstName") + " " + this.get("lastName");
}.property("firstName", "lastName"),
//defining the 'Details' as computed property fucntion
Details: function () {
return (
"Name: " +
this.get("Person") +
" Age: " +
this.get("age") +
" Mob No: " +
this.get("mobno")
);
}.property("Person", "age", "mbno"),
});
//initializing the Person details
var emp = App.Person.create({
//Dynamically Updating the properties
firstName: "Manu",
lastName: "DK",
age: 24,
mobno: "8792227920",
});
//setting the updated value for 'firstName'
emp.set("firstName", "Jhon");
document.write("Details of employee:" + emp.get("Details")); //dynamically updated values
//Details of employee:Name: Jhon DK Age: 24 Mob No: 8792227920 输出
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 对象模型setter和getter
Setter和Getter用于管理在computed属性中声明的变量的值。Ember.js set()方法计算程序中指定的特定条件的值。 Ember.js get()方法从setter中获取值并显示。
App.Person = Ember.Object.extend({
fullName: function(key, value, previousValue)
{
//setter and getter
}.property('firstName', 'lastName')
});
2
3
4
5
6
App = Ember.Application.create();
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
//Defining the fullName computed property function
fullName: function (key, value, previousValue) {
//lenngth of argument must be > 5
if (arguments.length > 5) {
//spliting the details and storing it into the nameParts array
var nameParts = value.split(/\s+/);
this.set("firstName", nameParts[0]);
this.set("lastName", nameParts[1]);
}
return this.get("firstName") + " " + this.get("lastName");
}.property("firstName", "lastName"),
});
var emp = App.Person.create({ firstName: "Jhon", lastName: "DK" }); //initializing the values for variable
document.write(
"Details of the employee: <br>" +
"Name: " +
emp.get("firstName") +
" LastName: " +
emp.get("lastName")
); //displaying the values by get() method
// Details of the employee:
// Name: Jhon LastName: DK 输出
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 使用@each计算属性和聚合数据
computed属性访问数组中的所有项目以确定其值。它使得简单的添加项目和从数组中删除项目。依赖键包含特殊键 @each ,不要使用嵌套形式的@each。这将更新当前计算属性的binding和observer。
App = Ember.Application.create();
App.TodosController = Ember.Controller.extend({
todos:[
Ember.Object.create({ isDone: true }),
Ember.Object.create({ isDone: false }),
Ember.Object.create({ isDone: true })
],
remaining: function() {
var todos = this.get('todos');
return todos.filterBy('isDone', false).get('length');
}.property('todos.@each.isDone')
});
var car_obj = App.TodosController.create();
document.write("The remaining number of cars in todo list: "+car_obj.get('remaining'));
2
3
4
5
6
7
8
9
10
11
12
13
14
在上面的代码中, todos*.**@each.isDone* 依赖项键包含一个特殊键@each。当您从Todo中添加和删除内容时,此键激活观察器。它将在剩余的计算属性中更新。
# 观察器
观察器更新计算属性的文本。它在文本更新或更改时触发。
App = Ember.Application.create();
App.Person = Ember.Object.extend({
Name: null,
fullName: function() {
var Name = this.get('Name');
return Name;
}.property('Name'),
NameChanged: function() {
document.write("Name is Updated: ");
this.set('Name','Jhon')
}.observes('fullName').on('init')
});
var person = App.Person.create({
Name: 'Yudistra'
});
document.write(person.get('fullName'));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在上面的代码中,
- 计算的属性函数 fullName 具有称为 Name 的变量。这最初将值保存为 Yudistra 。
- NameChanged computed属性函数将 Name 变量设置为具有 observer 属性的新名称 Jhon 。此属性在更改名称值期间触发,并将值分配给 fulName 计算的属性函数。
# 观察者的属性
观察器和异步 (opens new window) Ember.js中的观察器当前是同步的。
声明观察器 (opens new window) 声明一个没有原型扩展和类定义之外的obsever。
# 对象模型观察器和异步
Ember 为包括计算后属性在内的任意一种属性提供了观察器。可以通过使用 addObserver 方法来为一个对象设置一个观察器:
Person = Ember.Object.extend({
// 这些属性将由 `create` 提供
firstName: null,
lastName: null,
fullName: function() {
var firstName = this.get('firstName');
var lastName = this.get('lastName');
return firstName + ' ' + lastName;
}.property('firstName', 'lastName'),
fullNameChanged: function() {
// 处理改变
}.observes('fullName').on('init')
});
var person = Person.create({
firstName: "Yehuda",
lastName: "Katz"
});
person.set('firstName', "Brohuda"); // 观察器将被触发
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
由于 fullName 这个计算后属性依赖于 firstName 的变化,所以在更新 firstName 时也将触发 fullName 上的观察器。
# 观察器与异步
Ember中的观察器目前都是同步的。这就意味着一旦其观察的属性发生改变就立刻会被触发。因为这样,找到属性没有被及时同步就变得容易了:
Person.reopen({
lastNameChanged: function() {
// 该观察器和 fullName 都依赖于 lastName。因为观察器都是异步的,当该函数被调用时,
// fullName 还没有被更新,因此这里会打印出 fullName 的旧值。
console.log(this.get('fullName'));
}.observes('lastName')
});
2
3
4
5
6
7
如果观察了多个属性,那么同步行为也会导致观察器被多次触发:
Person.reopen({
partOfNameChanged: function() {
// 因为 firstName 和 lastName 都被设置了,将触发两次更新
}.observes('firstName', 'lastName')
});
person.set('firstName', 'John');
person.set('lastName', 'Smith');
2
3
4
5
6
7
8
为了处理这些问题,就需要使用 Ember.run.once 。这样可以确保所有需要处理的过程都只会发生一次,并且在下一个运行循环里面所有绑定都会同步:
Person.reopen({
partOfNameChanged: function() {
Ember.run.once(this, 'processFullName');
}.observes('firstName', 'lastName'),
processFullName: function() {
console.log(this.get('fullName')); // 如果两个属性都被设置,同步更新会一步到位
}
});
person.set('firstName', 'John');
person.set('lastName', 'Smith');
2
3
4
5
6
7
8
9
10
11
12
# 观察器与对象初始化
观察器只有对象完成了初始化过程之后才会被触发。
如果需要在初始化过程中就触发一个观察器,那么不能依赖于 set 的负效应。而应该在观察器上,通过使用**.on('init')**指定观察器应该在初始化后执行:
App.Person = Ember.Object.extend({
init: function() {
this.set('salutation', "Mr/Ms");
},
salutationDidChange: function() {
// 一些 salutation 的负效应正在改变
}.observes('salutation').on('init')
});
2
3
4
5
6
7
8
9
# 未使用的计算属性不触发观察器
如果从未 get 一个计算属性,那么即使它依赖的键发生改变了,观察器也不会被触发。可以认为这时是计算属性值从一个未知值转换为另一个。
这通常都不会影响到应用代码,因为计算属性几乎总是在被观察到的同时被取用。例如,取得一个计算属性的值,然后将其放入DOM中(或者用D3画出),然后观察它,以便在属性发生改变的时候自动更新DOM。
如果需要观察一个计算属性,当前并不获取它,只需要将其放入到 init 方法中。
# 不用原型扩展
在没有原型扩展的前提下使用 Ember 的时候,可以用 Ember.observer 方法来定义内联式观察器:
Person.reopen({
fullNameChanged: Ember.observer('fullName', function() {
// 这是内联式版本的 .addObserver
})
});
2
3
4
5
# 类定义之外
同样也可以在一个类的定义之外,使用 addObserver 为一个对象添加一个观察器:
person.addObserver('fullName', function() {
// 更新的处理
});
2
3
# 对象模型声明观察器
# 不带原型扩展
使用不带原型扩展的Ember.observer方法定义内联观察器。
App.ClassName = Ember.Object.extend({
ComputedPropertyName: Ember.observer('ComputedPropertyNames', function() {
//do the stuff
})
});
2
3
4
5
# 类定义之外
使用addObserver将观察器添加到类定义之外的对象
ClassName.addObserver('ComputedPropertyNames', function(){
//do the stuff
});
2
3
<script type="text/javascript">
App = Ember.Application.create();
App.Person = Ember.Object.extend({
Name: null,
fullName: function() {
var Name = this.get('Name');
return Name;
}.property('Name'),
fullNameChanged: Ember.observer('fullName', function(){
//deals with the change
})
});
var person = App.Person.create({ Name:'Manu',});
person.set('Name','Jhon');
document.write("Name Changed To: <br>");
document.write('Name: '+person.get('fullName'));//displaying changed value
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 相关链接
https://www.w3cschool.cn/emberjs/emberjs_overview.html