我觉得angularjs是前端框架,而jquery只是前端工具,这两个还是没有可比性的。
看知乎上关于jquery和angular的对比http://www.zhihu.com/question/27471743
优点:1. 模板功能强大丰富,并且是声明式的,自带了丰富的Angular指令;2. 是一个比较完善的前端MV*框架,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能;3. 自定义Directive,比jQuery插件还灵活,但是需要深入了解Directive的一些特性,简单的封装容易,复杂一点官方没有提供详细的介绍文档,我们可以通过阅读源代码来找到某些我们需要的东西,如:在directive使用 $parse;4. ng模块化比较大胆的引入了Java的一些东西(依赖注入),能够很容易的写出可复用的代码,对于敏捷开发的团队来说非常有帮助,我们的项目从上线到目前,UI变化很大,在摸索中迭代产品,但是js的代码基本上很少改动。5. 补充:Angular支持单元测试和e2e-testing。缺点:1. 验证功能错误信息显示比较薄弱,需要写很多模板标签,没有jQuery Validate方便,所以我们自己封装了验证的错误信息提示,详细参考 why520crazy/w5c-validator-angular · GitHub ;2. ngView只能有一个,不能嵌套多个视图,虽然有 angular-ui/ui-router · GitHub 解决,但是貌似ui-router 对于URL的控制不是很灵活,必须是嵌套式的(也许我没有深入了解或者新版本有改进);3. 对于特别复杂的应用场景,貌似性能有点问题,特别是在Windows下使用chrome浏览器,不知道是内存泄漏了还是什么其他问题,没有找到好的解决方案,奇怪的是在IE10下反而很快,对此还在观察中;4. 这次从1.0.X升级到1.2.X,貌似有比较大的调整,没有完美兼容低版本,升级之后可能会导致一个兼容性的BUG,具体详细信息参考官方文档 AngularJS ,对应的中文版本:Angular 1.0到1.2 迁移指南5. ng提倡在控制器里面不要有操作DOM的代码,对于一些jQuery 插件的使用,如果想不破坏代码的整洁性,需要写一些directive去封装插件,但是现在有很多插件的版本已经支持Angular了,如:jQuery File Upload Demo6. Angular 太笨重了,没有让用户选择一个轻量级的版本,当然1.2.X后,Angular也在做一些更改,比如把route,animate等模块独立出去,让用户自己去选择。当然使用的人多才会暴露更多的问题,一起为这些问题寻找解决方案是一个社区的良性趋势,选择Angular,的确使我们的开发效率大大提高。
2009年google feedback project 1500行
为了解决ajax开发的痛苦
1. 几个常用的概念
a.客户端模板:模板和数据都会发送到浏览器中
b.mvc:
c.数据绑定:自动将Model和view间的数据同步。
angular 实现数据绑定的方式,可以让我们把model当做程序中唯一可信的数据来源。view始终是model的投影。。当model发生变化时,会自动反映到view上。
大多数的数据绑定都是单向的,当我们的model和view修改后要去提醒另外一个的话,就必须使用ajax之类的,比如jquery还要手动的同步,这样子的话,增加了不必要的麻烦。
d.依赖注入:
2.依赖注入 的详解
回顾下spring中的ioc 控制反转:
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。
个人理解:就是本来需要你在程序设计时,创建的某些对象,交给spring来管理,当你需要某个时候需要某个对象的时候spring在给你,这样子对象的生命周期之类的就由spring来维护了。
var A = function () {
this.getName = function () {
return '张三';
}
}
var B = function (obj) {
// B 依赖于 a
document.write(obj.getName());
}
// a 注入 ba
var a = new A;
var b = new B(a);
========================
方法2:
var A = function () {
this.getName = function () {
return '张三';
}
}
var a = new A;
var B = function () {
// B 依赖于 a
document.write(a.getName());
}
// a 注入 ba
var b = new B(a);
===========================
3. 在 ng-app下
<input type="text" ng-model="name" value=""/>
<!--angular的表达式-->
{{ name }}
<input type="text" ng-model="name" value=""/>
这三个name的数据是绑定。
4. 控制器
<div ng-controller="firstController">
<input type="text" value="" ng-model="name"/>
<input type="text" value="" ng-model="age"/>
{{name}}
{{age}}
</div>
var firstController = function($scope){
// $scope 我们叫做作用域
// 申明一个Model
$scope.name = '张三';
$scope.age = 20;
}
5. 多个控制器
<div ng-controller="firstController">
<input type="text" value="" ng-model="name"/>
<div ng-controller="secondController">
<input type="text" value="" ng-model="name"/>
</div>
</div>
var firstController = function($scope){
$scope.name = '张三';
console.log($scope);
}
var secondController = function($scope){
console.log($scope);
}
6. $apply方法
var firstController = function($scope){
$scope.date = new Date();
// setInterval(function(){
// // 这里虽然变 但是并没有触发 脏检查
// $scope.date = new Date();
//
// },1000)
setInterval(function(){
$scope.$apply(function(){
$scope.date = new Date();
//....会去触发脏检查
})
},1000)
// 触发一次脏检查
}
7. watch
var firstController = function($scope){
$scope.name = '张三';
$scope.data = {
name :'李四',
count:20
}
$scope.count = 0;
// 监听一个model 当一个model每次改变时 都会触发第2个函数
$scope.$watch('name',function(newValue,oldValue){
++$scope.count;
if($scope.count > 30){
$scope.name = '已经大于30次了';
}
});
$scope.$watch('data',function(){
},true)
// 上面的true表示只要有一个true发生改变,那么这个watch就触发。
}
8. 一个简单的互动的demo代码
<div ng-controller="cartController" class="container">
<table class="table" ng-show="cart.length">
<thead>
<tr>
<th>产品编号</th>
<th>产品名字</th>
<th>购买数量</th>
<th>产品单价</th>
<th>产品总价</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in cart">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>
<button type="button" ng-click="reduce(item.id)" class="btn tn-primary">-</button>
<input type="text" value="{{item.quantity}}" ng-model="item.quantity" >
<button type="button" ng-click="add(item.id)" class="btn tn-primary">+</button>
</td>
<td>{{item.price}}</td>
<td>{{item.price * item.quantity}}</td>
<td>
<button type="button" ng-click="remove(item.id)" class="btn btn-danger">移除</button>
</td>
</tr>
<tr>
<td>
总购买价
</td>
<td>
{{totalPrice()}}
</td>
<td>
总购买数量
</td>
<td>
{{totalQuantity()}}
</td>
<td colspan="2">
<button type="button" ng-click="cart = {}" class="btn btn-danger">清空购物车</button>
</td>
</tr>
</tbody>
</table> <p ng-show="!cart.length">您的购物车为空</p>
</div>
var cartController = function ($scope) { $scope.cart = [
{
id: 1000,
name: 'iphone5s',
quantity: 3,
price: 4300
},
{
id: 3300,
name: 'iphone5',
quantity: 30,
price: 3300
},
{
id: 232,
name: 'imac',
quantity: 4,
price: 23000
},
{
id: 1400,
name: 'ipad',
quantity: 5,
price: 6900
}
]; /**
* 计算购物总价
*/
$scope.totalPrice = function () {
var total = 0;
angular.forEach($scope.cart, function (item) {
total += item.quantity * item.price;
})
return total;
} /**
* 计算总购买数
*/
$scope.totalQuantity = function () {
var total = 0;
angular.forEach($scope.cart, function (item) {
total += parseInt(item.quantity);
})
return total;
} /**
* 找一个元素的索引
*/
var findIndex = function (id) {
var index = -1; angular.forEach($scope.cart, function (item, key) {
if (item.id === id) {
index = key;
return;
}
}); return index;
} /**
* 为某个产品添加一个数量
*/
$scope.add = function (id) {
var index = findIndex(id); if (index !== -1) {
++$scope.cart[index].quantity;
}
} /**
* 为某个产品减少一个数量
*/
$scope.reduce = function (id) {
var index = findIndex(id); if (index !== -1) {
var item = $scope.cart[index];
if(item.quantity > 1){
--item.quantity;
}else{
var returnKey = confirm('是否从购物车内删除该产品!');
if(returnKey){
$scope.remove(id);
}
} }
} /**
* 移除一项
*/
$scope.remove = function (id) { var index = findIndex(id);
// 如果找到了那个item
if (index !== -1) {
$scope.cart.splice(index, 1);
} // 自动做脏检查
} // 监听数量 如果小于 1 则让用户判断是否要删除产品
$scope.$watch('cart',function(newValue,oldValue){ angular.forEach(newValue,function(item,key){
if(item.quantity < 1){
var returnKey = confirm('是否从购物车内删除该产品!');
if(returnKey){
$scope.remove(item.id);
}else{
item.quantity = oldValue[key].quantity;
}
}
})
},true);
//如果这个方式和上边的reduce同时执行的话,特别是reduce为0的时候, 先执行reduce方法,remove之后,执行这个函数的时候,就已经找不到那个cart中对应的值了,所以confirm不会重复弹出。 }
9. 控制器属于模块 。
模块是组织业务的一个框架,在一个模块当中定义多个服务。当引入了一个模块的时候,就可以使用这个模块提供的一种或多种服务了。
angularjs本身的一个默认模块叫做ng,它提供了$http,$scope等等服务。
服务只是模块提供的多种机制中的一种,其他的而还有指令(directive),
过滤器(filter),及其他配置信心。
也可以在已有的模块中新定义一个服务,也可以先定义一个模块,然后在新模块中定义新服务,。
服务是需要显示的声明依赖引入关系的,让ng自动地做注入。
<div ng-app="myApp"> <div ng-controller="firstController">
{{name}}
</div> </div>
var myApp = angular.module('myApp',[]); myApp.controller('firstController',function($scope){
$scope.name = '张三';
});
10.
$provide.service() 必须返回对象(数组也是对象),不能返回字符串之类的。
$provide.factory 这个可以返回任何类型。
var myApp = angular.module('myApp',[],function($provide){ // 自定义服务
$provide.provider('CustomService',function(){ this.$get = function(){
return {
message : 'CustomService Message'
}
}
}); // 自定义工厂
$provide.factory('CustomFactory',function(){
return [,,,,,,];
}); // 自定义服务
$provide.service('CustomService2',function(){
return 'aaa';
}) }); myApp.controller('firstController',function($scope,CustomFactory,CustomService2){
$scope.name = '张三'; console.log(CustomFactory); console.log(CustomService2); }); //myApp.service();
//myApp.factory();
11.
服务本身是一个任意的对象。
ng提供服务的过程涉及它的依赖注入机制。
angular 是用$provider对象来实现自动依赖注入机制,注入机制通过调用一个provider的$get方法,
把得到对象作为参数进行相关调用。
$provider.provider是一种定义服务的方法,$provider还提供了很多很多简便的方法,这些方法还被module所引用。
也许这里有人问:control层和service层的区别:
1.事务的回滚在service层,比如重定向之类的在control层。
var myApp = angular.module('myApp',[],function($provide){ // 自定义服务
//自定义服务本身就是一个服务,这个服务的数据可以设置也可以返回,而service和factoyr只能返回数据。
$provide.provider('CustomService',function(){ this.$get = function(){
return {
message : 'CustomService Message'
}
}
}); $provide.provider('CustomService2',function(){ this.$get = function(){
return {
message : 'CustomService2 Message'
}
}
});
}); myApp.controller('firstController',function(CustomService,$scope,CustomService2){
$scope.name = '张三'; console.log(CustomService2);
});
12. 多个控制器数据的共享两种方法:
$scope.data = $scope.$$prevSibling.data; 这样子必须是一个对象的值,在html页面的显示,必须是一个data.name这种形式,如果是data的话那么就不行。
<div ng-app="myApp"> <div ng-controller="firstController">
first.data <input type="text" ng-model="data.name" />
first.Data <input type="text" ng-model="Data.message" />
<p>
first-name:{{data.name}}
</p>
<p>
first-message:{{Data.message}}
</p>
</div> <div ng-controller="secondController">
<p>
second-name:{{data.name}}
</p>
<p>
second-message:{{Data.message}}
</p>
</div>
</div>
angular.module('myApp',[]) .factory('Data',function(){
// this.$get = function(){}
return {
message : '共享的数据'
};
}) .controller('firstController',function($scope,Data){
$scope.data = {
name : '张三'
}; $scope.Data = Data;
}) .controller('secondController',function($scope,Data){
$scope.data = $scope.$$prevSibling.data; $scope.Data = Data;
});
13. 过滤器:
angular.module('myApp',[]) .factory('Data',function(){ return {
message : '共享的数据'
};
}) .controller('firstController',function($scope,Data,$filter){
$scope.data = Data; $scope.today = new Date; })
<div ng-controller="firstController"> <!--123,456,789-->
<p>{{123456789 | number}}</p>
<!--12,345.679-->
<p>{{12345.6789 | number:3}}</p> <!--$999,999.00-->
<p>{{999999 | currency}}</p>
<!--rmb999,999.00-->
<p>{{999999 | currency:'rmb'}}</p> <p>
default:{{ today }}
</p> <p>
medium: {{ today | date:'medium'}}
</p> <p>
short:{{ today | date:'short'}}
</p> <p>
fullDate:{{ today | date:'fullDate'}}
</p> <p>
longDate:{{ today | date:'longDate'}}
</p> <p>
mediumDate:{{ today | date:'mediumDate'}}
</p> <p> shortDate:{{ today | date:'shortDate'}}
</p> <p>
mediumTime:{{ today | date:'mediumTime'}}
</p> <p>
shortTime:{{ today | date:'shortTime'}}
</p> <p>
year:
{{today | date : 'y'}}
{{today | date : 'yy'}}
{{today | date : 'yyyy'}}
</p>
<p>
month:
{{today | date : 'M'}}
{{today | date : 'MM'}}
{{today | date : 'MMM'}}
{{today | date : 'MMMM'}}
</p>
<p>
day:
{{today | date : 'd'}}
Day in month {{today | date : 'dd'}}
Day in week {{today | date : 'EEEE'}}
{{today | date : 'EEE'}}
</p> <p>
hour:
{{today | date : 'HH'}}
{{today | date : 'H'}}
{{today | date : 'hh'}}
{{today | date : 'h'}}
</p> <p>
minute:
{{today | date : 'mm'}}
{{today | date : 'm'}}
</p> <p>
second:
{{today | date : 'ss'}}
{{today | date : 's'}}
{{today | date : '.sss'}}
</p> <p>
{{today | date : 'y-MM-d H:m:s'}}
</p> </div>
14. 更多的选择器:
原始数据类型:
<div ng-controller="firstController"> <!--[,,,,]-->
<p>{{[,,,,,,] | limitTo:}}</p> <!--[,,,,]-->
<p>{{[,,,,,,] | limitTo:-}}</p> <!-- hello world -->
<p>{{data.message | lowercase}}</p>
<!-- HELLO WORLD -->
<p>{{data.message | uppercase}}</p> <p>
<!-- [{"name":"上海11212","py":"shanghai"}]-->
{{ data.city | filter : '上海'}}
</p>
<p>
<!-- []-->
{{ data.city | filter : 'name'}}
</p> <p>
<!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}-->
{{ data.city | filter : {py:'g'} }}
</p> <p>
<!-- name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}-->
{{ data.city | filter : checkName }}
</p> <p>
<!-- [{"name":"北京","py":"beijing"},{"name":"上海11212","py":"shanghai"},{"name":"四川","py":"sichuan"}] -->
<!-- 默认顺序是 正序 asc a~z -->
{{ data.city | orderBy : 'py'}} <!-- 默认顺序是 反序 desc z~a -->
<!-- [{"name":"四川","py":"sichuan"},{"name":"上海11212","py":"shanghai"},{"name":"北京","py":"beijing"}] -->
{{ data.city | orderBy : '-py'}}
</p>
angular.module('myApp',[]) .factory('Data',function(){ return {
message : 'Hello World',
city : [
{
name:'上海11212',
py : 'shanghai'
},
{
name:'北京',
py : 'beijing'
},
{
name:'四川',
py : 'sichuan'
}
]
};
}) .controller('firstController',function($scope,Data,$filter){
$scope.data = Data; $scope.today = new Date; // 过滤器
var number = $filter('number')(); var jsonString = $filter('json')($scope.data); console.log(jsonString);
console.log($scope.data); $scope.checkName = function(obj){
if(obj.py.indexOf('h') === -)
return false;
return true;
} })
15. 自定义的过滤器
<div ng-controller="firstController">
<ul>
<li ng-repeat="user in data | filterAge">
{{user.name}}
{{user.age}}
{{user.city}}
</li>
</ul>
</div>
var myApp = angular.module('myApp', [], function ($filterProvider, $provide, $controllerProvider) { $provide.service('Data', function () {
return [
{
name: '张三',
age: '',
city: '上海'
},
{
name: '李四',
age: '',
city: '北京'
}
]; }); $filterProvider.register('filterAge', function () {
return function (obj) {
var newObj = []; angular.forEach(obj, function (o) {
if (o.age > ) {
newObj.push(o);
}
}); return newObj; }
}); $controllerProvider.register('firstController', function ($scope, Data) {
$scope.data = Data;
}) }) // module.filter
.filter('filterCity',function(){
return function(obj){
var newObj = []; angular.forEach(obj, function (o) {
if (o.city === '上海') {
newObj.push(o);
}
}); return newObj;
}
})
16.正确的使用controller
正确的使用controller
controller不应该尝试做太多的事情。它应该仅仅包含单个视图所需要的业务逻辑,保持controller的简单性,常见办法是抽出不属于controller的工作到service中,在controller通过依赖注入来使用service。
不要在controller中做以下的事情:
1.任何类型的DOM操作-controller应该仅仅包含业务逻辑,任何表现逻辑放到controller中,大大地影响了应用逻辑的可测试性。angular为了自动操作(更新)DOWM,提供的数据绑定。如果希望执行我们自定义的DOM操作,可以把表现逻辑抽取到directive中。
2.input formatting(输入格式化) 使用angular form controls代替。
3.output filtering(输出格式化过滤) 使用angular filters.
4.执行无状态或有状态的,controller共享的代码--使用angular services代替。
5. 实例化或者管理其他组件的生命周期。(例如创建一个服务实例)
17.代码的显示注入和隐式注入
var myApp = angular.module('myApp', [], ['$filterProvider', '$provide', '$controllerProvider', function (a, b, c) {
console.log(a, b, c);
}]) .
factory('CustomService', ['$window', function (a) {
console.log(a);
}]) // 隐示的依赖注入
.controller('firstController', function ($scope, CustomService) {
console.log(CustomService);
}) // 显示的依赖注入
.controller('secondController', ['$scope', '$filter', function (a, b) {
console.log(b('json')([, , , , ]));
}]); function otherController(a) {
console.log(a);
} otherController.$inject = ['$scope'];
18. 内置指令:
渲染指令:
ng-init
ng-bind
ng-repeat
$index 当前索引
$first 是否为头元素
$middle 是否为非头非尾元素
$lasth是否为尾元素
ng-include
ng-bing-template.
ng-bind
ng:bind
data-ng-bind
x-ng-bind
事件指令:
ng-change
ng-click
ng-dblclick
ng-mousedown
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
ng-mouseup
ng-submit
节点指令
ng-style
ng-class
ng-class-even
ng-class-odd
这里的red表示style中的类,而-even表示在偶数列会添加这个class.
ng-show
ng-hide
ng-switch
ng-src
ng-href
ng-if
==
.red{color:red;}
ng-class='{red:status}'
什么是指令:
可以利用指令来扩展HTML标签,增加声明式语法来实现想做的任何事,可以对应用有特殊意义的元素和属性来替换一般的HTML标签。
angular 也内置了非常堵偶的指令,ng-app ,ng-controller.
ngsrc 延迟加载。等angular加载完然后加载。这个属性。
<div ng-app="myApp"> <div ng-controller="firstController">
<p>{{+}}</p>
<p ng-bind="1+1"></p>
<p ng-bind-template="{{1+1}}"></p> <!-- $scope.cityArr = ['上海','北京','杭州'] -->
<ul ng-class="{red:status}" ng-init="cityArr = ['上海','北京','杭州']">
<li ng-class-even="'偶数'" ng-class-odd="'奇数'" ng-repeat="city in cityArr" >
<span>
index:{{$index}}
</span>
<span>
first:{{$first}}
</span>
<span>
middle:{{$middle}}
</span>
<span>
last :{{$last}}
</span>
<span>
{{city}}
</span>
</li>
</ul> <div ng-include="'other.html'"> </div> <div ng-include src="'other.html'"> </div> </div>
</div>
var myApp = angular.module('myApp', []) .controller('firstController', function ($scope) {
$scope.status = false; $scope.changeStatus = function (event) {
// 通过element转换成 jquery对象
angular.element(event.target).html('切换状态为:' + $scope.status); $scope.status = !$scope.status; } $scope.defaultStyle = {
color: 'red',
'margin-top': '50px'
}; $scope.src = 'http://www.angularjs.org/img/AngularJS-large.png';
})
$scope.changeStatus 这个会自动触发脏检查。
ng-style="{color:'red','margin-top':'50px'}" 后边这个注意加单引号。
19. 自定义的指令:
自定义过滤器,factory,service.
templateUrl:加载模板所要使用的URl
可加载当前模板对应的text/ng-template script id
在使用chrome浏览器时,‘同源策略’会阻止chrome从file://中加载模板,并显示一个"Acces-Control-Allow-Origin"不允许源为null,可以把项目放在服务器上加载,命令为:chrome -allow-file-access-from-files
<div ng-app="myApp"> <custom-tags></custom-tags> <div class="custom-tags"> </div> <div custom-tags> </div> <!-- directive:custom-tags -->
</div>
var myApp = angular.module('myApp', [], ['$compileProvider',function ($compileProvider) { $compileProvider.directive('customTags',function(){
return {
restrict:'ECAM',
template:'<div>custom-tags-html</div>',
replace:true //这个属性对于E这种指令适用,可以提现出来
}
}); }]) //.directive('') 这是一种简单的写法
20.transclude:true保留原始数据
21.优先级(不是很重要)
priority && terminal
priority 设置指令在模板中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行。
设置优先级的情况比较少,象ng-repest,在遍历元素的过程中,需要angular先拷贝生成的模板元素,在应用其他指令,所以ng-repeat默认的priority是1000
terminal是否当前指令的权重为结束界限,如果这值设置为true,则节点中权重小于当前指令的其他指令不会被执行。相同权重的会执行。
22.
angularjs指令编译三阶段
1.标准浏览器API转化。
将html转化成dom,所以自定义的html标签必须符合html的格式。
2.angular compile
搜索匹配directive,按照priority排序,并执行directive上的compile方法。
3.angular link
执行directive上的link方法,进行scope绑定及事件绑定。
directive可以配置的指令:
priority
template
terminal
templateUrl
scope
replace: 是否替换当前html标签
controller
transclude
controllerAs
compile
require
link
restrict
23.
compile
compile:function(tElement,eAttrs,transclude)
compile函数用来对模板自身进行转换,仅仅在编译阶段运行一次,
compile中直接返回的函数是postLink,表示参数需要执行的函数,也可以返回一个对象里边包含preLink和postLink,
当定义compile参数时,将无视link参数,因为compile里返回的就是该指令需要执行的link函数。
24.
一个标签有两个指令的话,最好有一个template(多的情况不常用)
compile返回的就是link函数,所以说定义了compile就不用定义link.
compile的三个参数,(tElement,eAttrs,transclude)
eElement是angular内置的jquery的一个对象所以可以调用eElement.append的方法。
compile 和link的使用时机
compile想再dom渲染前对它进行变形,并且不需要scope参数想在所有相同directive里共享某些方法,这时应该定义compile里,性能会比较好,返回值就是link的function,这时就是共同使用的时候。
link 对特定的元素注册事件。
需要用到scope参数来实现dom元素的一些行为。
如果在你的directive的返回不是一个对象,而是返回的是一个匿名方法的话,这个方法就是postLink方法。或者说就是Link,link就是postLink。
link(scope,iElement,iAttrs, controller)
link参数代表的是compile返回的postLink
preLink表示在编译阶段之后,指令练级到子元素之前运行。
postLink 表示会在所有子元素指令都连接之后才运行
link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次。
25.
<div ng-app="myApp"> <div ng-controller="firstController">
<!--
. div 转换为dom结构
. 默认的优先级为0,哪个先定义哪个先使用 -->
<div ng-repeat="user in users" custom-tags="" custom-tags2> </div> </div> </div>
var i = ; var myApp = angular.module('myApp', []) .directive('customTags',function(){
return {
restrict : 'ECAM',
template : '<div>{{user.name}}</div>',
replace : true,
compile:function(tElement,tAttrs,transclude){ tElement.append(angular.element('<div>{{user.name}}{{user.count}}</div>')); // 编译阶段...
console.log('customTags compile 编译阶段...'); return {
// 表示在编译阶段之后,指令连接到子元素之前运行
pre:function preLink(scope,iElement,iAttrs,controller){
console.log('customTags preLink..')
},
// 表示在所有子元素指令都连接之后才运行
post:function postLink(scope,iElement,iAttrs,controller){ iElement.on('click',function(){
scope.$apply(function(){
scope.user.name = 'click after';
scope.user.count = ++i;
// 进行一次 脏检查
});
}) console.log('customTags all child directive link..')
}
}
// 可以直接返回 postLink
// return postLink function(){
// console.log('compile return fun');
//}
},
// 此link表示的就是 postLink
link:function(){
// iElement.on('click',function(){
// scope.$apply(function(){
// scope.user.name = 'click after';
// scope.user.count = ++i;
// // 进行一次 脏检查
// });
// })
}
}
}) .directive('customTags2',function(){
return {
restrict : 'ECAM',
replace : true,
compile:function(){
// 编译阶段...
console.log('customTags2 compile 编译阶段...'); return {
// 表示在编译阶段之后,指令连接到子元素之前运行
pre:function preLink(){
console.log('customTags2 preLink..')
},
// 表示在所有子元素指令都连接之后才运行
post:function postLink(){
console.log('customTags2 all child directive link..')
}
} }
}
}) .directive('customTags3',function(){ // return postLink;
return function(){ }
}) .controller('firstController', ['$scope', function ($scope) {
$scope.users = [
{
id:,
name:'张三'
},
{
id:,
name:'李四'
}
];
}]);
26.
controller && controllerAds && require
controller他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信
controller($scope,$element,$transclude)
controllerAs是给controller起个别名,方便使用
require可以将其他指令传递给自己
directiveName: 通过驼峰法的命名指定了控制器应该带有哪一条指令,默认会从同一个元素上的指令
^directiveName: 在父级朝找指令
?directiveName:表示指令是可选的,如果找不到,不需要抛出移除。
27.自定义指令:controllerAs 和link,可以使用上面的controller中的属性方法
angular.module('myApp', []) .directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
];
$scope.addBook = function(){ }
this.addBook = function(){
// ...
}
},
controllerAs:'bookListController',//上边 controller的别名,下边的link或者compile可以使用
template: '<ul><li ng-repeat="book in books">{{book.name}}</li></ul>',
replace:true,
link:function(scope,iEelement,iAttrs,bookListController){
//上边的iEelement表示的是template中的内容和jquery中的一样,bookListController表示的上边的controllerAs,
// 如果调用this.addBook,你直接用bookListController.addBook,如果调$scope.addBook iEelement.on('click',bookListController.addBook) } } })
.controller('firstController', ['$scope', function ($scope) { // console.log($scope);
//这里写的controller代码和上边的controller写是一样的效果 }]);
28. require的用法
记住1.require后边的需要有一个引号。2.后面也需要一个引号。3.addBook方法是写在this上而不是写在scope上额。
angular.module('myApp', []) .directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) {
$scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
]; this.addBook = function(){ $scope.$apply(function(){
$scope.books.push({
name:'Angularjs'
})
});
}
},
controllerAs:'bookListController',
template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul><book-add></book-add></div>',
replace:true } }) .directive('bookAdd',function(){
return {
restrict:'ECAM',
require:'^bookList',
template:'<button type="button">添加</button>',
replace:true,
link:function(scope,iElement,iAttrs,bookListController){
iElement.on('click',bookListController.addBook);
}
}
}) .controller('firstController', ['$scope', function ($scope) {
// console.log($scope); }]);
这里我们可以看到require可以继承父类的controller方法,和属性。注意^bookList继承父类的。
require的作用是为了让父子指令或者兄弟指令的controller之间搭建一个桥梁
也就是说父指令里的controller里面的数据能分享给子指令的controller
其中子指令的link第四个参数的值是父指令的controller对象的作用域上下文
require有两个修饰符号:”?”、”^”
? : 如果require没有找到相应的指令避免报错,还能确保程序的正常执行
^ : 表示往父级查找
?^可以一起使用
29.scope 中@只能是值的绑定(简单数据类型的绑定)而&却可以是对象的绑定。注意对象html页面中的内容。如果是一个对象的话,我们需要先把父类的controller中的东西放到一个属性中,然后我们的子controller然后从html标签中的属性中取值,然后付给自己的属性。
scope(是针对子controller与父controller,但是我们需要注意的时候与reqiuire的区别是,require为了link中的第四个参数提供服务,而我们的scope则需要把属性绑定到html的属性上边)
这里我们可以看出来,如果books是object类型,而title是简单数据类型。
scope:为当前指令创建一个新的作用域,而不是使之继承父作用域 默认值记不清了
false继承父元素的作用域,和父共享一个作用域
true创建一个新的作用域,但是还是会继承父作用域的属性,
object也是创建一个独立的scope但是也可以通过一些方式继承父类
object:参数
& 作用域把父作用域的属性包装成一个函数,从而以函数的方法会读写父作用域的属性。 注意这里的单项绑定是方法,下边的双向绑定确实一个属性。
=:作用域的属性与父作用域的属性进行双向绑定,任何一方的修改均影响到对方。
@: 只能读取父作用域里的值单向绑定。
<div ng-app="myApp"> <div ng-controller="firstController">
{{
books
}}
<div book-list books="books" parent-books="books" parent-title="{{title}}"> <!--注意这里的title有{{}},简单数据类型绑定属性的时候有,而负责的数据类型则没有--> </div> </div> </div>
angular.module('myApp', []) .directive('bookList', function () {
return {
restrict: 'ECAM',
controller: function ($scope) { // &books
// $scope.books = $scope.a(); // =books;
// $scope.books = $scope.b;
// $scope.b.push({name:'nodejs'}); console.log($scope.c); },
// 创建一个有继承链的独立作用域
// scope:true, // 当为对象的时候也会创建一个独立的作用域
scope:{
// 将父元素books封装成一个a函数
// a:'&books'
// 双向绑定 b = parentBooks属性对应的父作用域的表达式
// b:'=parentBooks' // 使用简单数据类型的方法
c:'@parentTitle'
},
controllerAs:'bookListController',
template: '<div><ul><li ng-repeat="book in books">{{book.name}}</li></ul></div>',
replace:true } }) .controller('firstController', ['$scope', function ($scope) {
console.log($scope); $scope.books = [
{
name: 'php'
},
{
name: 'javascript'
},
{
name: 'java'
}
]; $scope.title = '张三'; }]);
30.自定义
嵌套的directive
heading:@heading 可以简写成heading:@
<div ng-app="myApp"> <div class="container">
<div ng-controller="firstController"> <kittencup-group> <kittencup-collapse ng-repeat="collapse in data" heading="{{collapse.title}}">
{{collapse.content}}
</kittencup-collapse> </kittencup-group> </div>
</div> </div>
angular.module('myApp', [])
// 数据
.factory('Data', function () {
return [
{
title: 'no1',
content: 'no1-content'
},
{
title: 'no2',
content: 'no2-content'
},
{
title: 'no3',
content: 'no3-content'
}
];
})
// 控制器
.controller('firstController', ['$scope','Data',function ($scope,Data) {
$scope.data = Data;
}]) .directive('kittencupGroup',function(){
return {
restrict:'E',
replace:true,
template:'<div class="panel-group" ng-transclude></div>',
transclude:true,
controllerAs:'kittencupGroupContrller',
controller:function(){
this.groups = []; this.closeOtherCollapse = function(nowScope){
angular.forEach(this.groups,function(scope){
if(scope !== nowScope){
scope.isOpen = false;
}
})
}
}
}
}) .directive('kittencupCollapse',function(){
return {
restrict:'E',
replace:true,
require:'^kittencupGroup',
templateUrl:'app/tmp/kittencupCollapse.html',
scope:{
heading:'@'
},
link:function(scope,element,attrs,kittencupGroupContrller){
scope.isOpen = false; scope.changeOpen = function(){
scope.isOpen = !scope.isOpen; kittencupGroupContrller.closeOtherCollapse(scope);
} kittencupGroupContrller.groups.push(scope);
},
transclude:true
}
})
一段angular指令自己平时练习的代码:
var ng = angular.module('box',[]);
ng.directive('aa',function(){
return {
restrictive:"ECAM",
template:"<div><h2>this is our world {{data}}</h2><span ng-transclude></span><bb data='data' title='{{title}}'></bb></div>",
replace: true,
transclude:true,
controller:function($scope){
$scope.data = {'key':"beautiful"}
this.al = function(){
alert(1234);
}
$scope.title = "title";
},
controllerAs:"aacontroller"
}
})
ng.controller('first',function($scope){ });
ng.directive('bb',function(){
return{
restrictive:"ECAM",
require:'^?aa',
template:"<div>this is son directive {{data}}<input ng-model='data'/></div>",
replace: true,
controller:function($scope){
$scope.data = $scope.a;
},
scope:{
a:'@title'
},
link:function(scope,el,attr,aacontroller){
//el.on('click',aacontroller.al);
}
}
});
32.优先级,小于0的不执行
<div ng-controller="firstController">
<custom-tags>原始数据</custom-tags> <div custom-tags2 custom-tags3> </div>
</div>
var myApp = angular.module('myApp', []) .directive('customTags', function () {
return {
restrict: 'ECAM',
template:'<div>新数据 <span ng-transclude></span></div>',
replace: true,
transclude:true
}
}) .directive('customTags2', function () {
return {
restrict: 'ECAM',
template:'<div>2</div>',
replace: true,
priority:-
}
}) .directive('customTags3', function () {
return {
restrict: 'ECAM',
template:'<div>3</div>',
replace: true,
priority: ,
// 小于0的directive 都不会执行
terminal:true
}
}) .controller('firstController', ['$scope', function ($scope) {
$scope.name = '张三';
}]);
33. $scope相当于js对象继承的作用域链
34.
$provide方法都有快捷方法。
constant(name,object)
此方法首先运行,可以用它来声明整个应用范围内的常量,并且让它们在所有配置(config方法里)和实例(controller,service等)方法中都可用。
run(initializationFn)
想要在注入启动之后执行某些操作,而这些操作需要在页面对用户可用之前执行,可以使用此方法。
比如 加载远程的模板,需要在使用前放入缓存,或者在使用操作前判断用户是否登录,未登录可以先去登录页面。
angular.module('myApp',[],['$provide',function($provide){
console.log('config');
// $provide.factory
// $provide.service // $provide.constant
// $provide.value; }]) .config(function(APIKEY){
console.log(APIKEY);
console.log('config');
}) // 在config之后controller等其他服务之前。。
.run(function(){
console.log('run');
})
// 它只是可以注入任何方法
.constant('APIKEY','xxxx') // 只能注入controller...service factory
.value('vension','1.0.0') .controller('firstController',['APIKEY','vension',function(APIKEY,vension){
console.log(APIKEY);
console.log(vension);
console.log('controller'); }]);
35. ng-show ng-hide ng-if 可以看:http://m.blog.csdn.net/article/details?id=44701769
angularJS中的ng-show、ng-hide、ng-if指令都可以用来控制dom元素的显示或隐藏。ng-show和ng-hide根据所给表达式的值来显示或隐藏HTML元素。当赋值给ng-show指令的值为false时元素会被隐藏,值为true时元素会显示。ng-hide功能类似,使用方式相反。元素的显示或隐藏是通过改变CSS的display属性值来实现的。
ng-if指令可以根据表达式的值在DOM中生成或移除一个元素。如果赋值给ng-if的表达式的值是false,那对应的元素将会从DOM中移除,否则生成一个新的元素插入DOM中。ng-if同no-show和ng-hide指令最本质的区别是,它不是通过CSS显示或隐藏DOM节点,而是删除或者新增结点。
36.服务返回一种方法的时候 http://www.runoob.com/try/try.php?filename=try_ng_services_filter2
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body> <div ng-app="myApp" ng-controller="myCtrl">
<p>在获取数组 [, , ] 值时使用过滤器:</p> <ul>
<li ng-repeat="x in counts">{{x | myFormat}}</li>
</ul> <p>过滤器使用服务将10进制转换为16进制。</p>
</div> <script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString();
}
});
app.filter('myFormat',['hexafy', function(hexafy) {
return function(x) {
return hexafy.myFunc(x);
};
}]);
app.controller('myCtrl', function($scope) {
$scope.counts = [, , ];
});
</script> </body>
</html>
一下就是自己angular开发中,常遇到的一些问题
37.如果ul li中的li点击事件,本来想在Link中直接写一个类型ul.find('li').on的发现不行的,只能在页面的li中写一个方法,并且传入$event.利用
// 通过element转换成 jquery对象
angular.element(event.target).html('切换状态为:' + $scope.status);
38.$scope与this的区别。
(1)$scope会继承,但是this不会。
(2)在两个directive中,如果一个directive通过require引用另外一个directive中的东西,那么方法必须写在this中,如果写在$scope中则不行。
39.const run value这个方法的区别和联系。
config先执行,而run在config之后在controller等其他服务之前。。
const value
但是const只能注入方法中,
value// 只能注入controller...service factory
40.transclude:true实现的在于必须外边的controller是有定义的,如果外边的controller没有定义没效果.
41.AngularJS的学习 $on、$emit和$broadcast的使用
不过用的是$scope 发射和接受。
emit(name,data)向父control发射的。
而broadcast(name,data)是向子control发射的。