一、ng的四大特性
1.MVC:
MVC是一种设计模式?它的使用让代码变得模块化,职责清晰。M(Model)即数据模型层,它用于数据结构的组织,数据的获取和存储;V(View)即视图,网页上我们所能看到部分就是视图;C(Controller)即控制器,它提供了业务逻辑和控制逻辑,同时与模型层和视图两部分进行交互。
2.模块化:
ng的模块化特性使其代码得以复用。模块化特性也是我们在使用ng编写程序时首先应当要明确的内容。ng将网站分成一个个模块,控制器、指令、服务等组件作为方法供其调用。
3.指令系统:
ng用指令(directive)系统扩展了HTML标签,它不仅能提供丰富的标签模板,还能把方法封装到其中,大大精简了HTML中的编码量。简单的指令示例如下:
myModule.directive('hello',function(){
return {
restrict:'EA',
template:'<div>Hello,Angular</div>',
replace:true
}
});
上面的代码段定义了hello
指令,restrict
属性规定了它能被当成属性或者元素被调用,HTML中的使用方式如下:
<hello></hello>
`显而易见,页面上显示的内容为:
<div>Hello,Angular</div>
4.双向数据绑定
单向数据绑定即当数据模型发生变化时,视图上的内容也相应的变化,反之不成立。双向数据绑定不仅能让数据模型影响视图内容,也能让视图内容的变化改变数据模型层。ng通过几个指令和代码编写方式来使用双向数据绑定:使用ng-bind
和双花括号{{ }}
能把程序中的数据发送到页面的元素中,使用ng-model
可以从页面中提取到数据并存储到程序中。此处的程序指的是$scope
。通过双向数据绑定,可以非常便捷的记录并处理用户在表单中的输入。
二、MVC
1.Controller
每一个控制器都只控制一部分视图,不能复用controller;DOM操作不建议放到controller中,而应将这些操作过程封装于指令中;不用controller做数据格式化或者过滤,因为有更好的组件如filter。控制器的定义和使用如下:
myModule.controller('myCtrl',['$scope',function($scope){
$scope.name='MY';
}]);
<div ng-controller='myCtrl'>{{name}}</div>
controller实际上是一个函数,它所调用的参数需要在中括号中指定,本例中仅仅调用了`$scope`参数。创建controller后,将为其生成一个`$scope`的作用域,该controller管控下的变量以及函数均存在该作用域中。本例中,`name`变量即存在`$scope`中。
2.Model
ng-model挂在$rootscope
对象上。
3.View
ng的MVC由$scope
实现。$scope
由层级结构,引用其中的变量或者函数的时候会逐级往上查询,子$scope
会继承父$scope
上的变量和方法。$scope
是POJO(Plain Old JavaScript Object),它提供了工具方法watch
和apply
,可以向上(emit)或者向下(broadcast)传播事件。
三、模块化
ng中的模块类似于一个容器,可以把模型、视图、控制器、过滤器等组件装到其中。模块的定义方式如下,第一个参数是模块名称,第二个中括号中可以加入该模块依赖的其他模块。
var myModule=angular.module('MyModule',[ ]);
多个controller模块时,如何切分(加载)? 根据站点的功能划分模块,为每一个模块分别定义控制器以及过滤器等。最后把这些模块以依赖注入的形式在主模块中声明即可。自定义的模块通常放在依赖列表的最后项。
四、指令
1.真实开发工作中,很大部分时间都在编写和使用指令。
2.指令的定义:
myModule.directive('hello',function(){
return {
scope:{},
restrict:'EA',
transclude:true,
replace:true,
template:'<div>Hello,Angular<div ng-transclue></div></div>',
controller:function($scope){
$scope.attr=[];
this.addAttr=function(){
$scope.attr.push('attr')
}
},
link:function(scope,element,attrs){
scope.$apply(***);
scope.addClass('btn btn-primary');
element.bind('mouseenter',function(){});
}
}
});
scope
属性给该指令划定了独立作用域,区别于全局的$scope作用域,使得hello指令拥有独立的变量以及方法;
restrict
属性限定指令的使用方式,有EACM种,分别对应于Element、Attribute、Class和Comment,他们的调用方式如下:
<hello></hello>
<div hello></div>
<div class='hello'></div>
<!-- directive:hello -->
transclude
属性表示将HTML指令中原有的内容填充到template
中带有ng-transclude
属性的标签中;
replace
属性表示是否以template中的内容替换HTML中指令;
controller
属性中的变量和方法为该指令所特有的;
link
属性中可以调用函数,这些函数可能来自于$socpe,来自于本指令中。同时,也可在link中绑定事件监听器。
3.指令的执行过程
加载——编译——链接。加载过程识别Angular应用边界;编译过程遍历DOM,找到所有指令,根据template
、replace
和transclude
等属性替换DOM;link
中函数的调用。
4.指令与控制器的交互
这里的控制器指的是$socpe
中的控制器。比如指令调用$scope中定义的一个方法可以这么写:
myModule.controller('myCtrl',function($scope){
$scope.loadData()=function(){
console.log('数据加载中…');
}
});
myModule.directive('loader',function(){
restrict:'EA',
replace:true,
transclude:true,
template:'<div ng-transclude></div>'
link:function(scope,element,attr){
element.bind('mouseenter',function(){
scope.loadData();
});
}
})
<div ng-controller='myCtrl'>
<loader>滑动</loader>
</div>
假如有一个myCtrl2控制器中的loader指令想调用其中定义的loadData2方法,用上述的link
方式无法完成,需要改造该函数以实现复用。
<div ng-controller='myCtrl2'>
//把函数封装成指令的一个属性并调用
<loader howToLoad='loadData2()'>滑动</loader>
</div>
link:function(scope,element,attrs){
element.bind('mouseenter',function(){
//attrs后的方法名无括号,并且驼峰写法改成小写
scope.$apply(attrs.howtoload);
});
}
5.指令之间的交互
指令之间的交互发生在存在依赖关系的指令之间。被依赖的指令中用controller定义一些函数暴露给依赖指令调用。
myModule.directive('superman',function(){
return {
scope:{},
restrict:'EA',
controller:function($scope){
$scope.abilities=[];
this.addStrength=function(){
$scope.abilities.push('strength');
};
this.addSpeed=function(){
$scope.abilities.push('speed');
};
},
link:function(scope,element,attrs)
element.addClass('btn btn-primary');
element.bind('mouseenter', function () {
console.log(scope.abilities);
})
}
}
});
myModule.directive('strength', function () {
return {
//第四个supermanCtrl是被依赖指令中定义的controller
link: function (scope, element, attrs, supermanCtrl) {
supermanCtrl.addStrength();
}
}
});
myModule.directive('speed', function () {
return {
require: '^superman',
link: function (scope, element, attrs, supermanCtrl) {
supermanCtrl.addSpeed();
}
}
});
<superman strength>超人--力量</superman><br>
<superman strength speed>超人--力量和速度</superman>