我以爲angularjs是前端框架,而jquery只是前端工具,這兩個仍是沒有可比性的。javascript
看知乎上關於jquery和angular的對比http://www.zhihu.com/question/27471743php
優勢: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,的確使咱們的開發效率大大提升。html
2009年google feedback project 1500行
爲了解決ajax開發的痛苦前端
1. 幾個經常使用的概念
a.客戶端模板:模板和數據都會發送到瀏覽器中
b.mvc:
c.數據綁定:自動將Model和view間的數據同步。
angular 實現數據綁定的方式,可讓咱們把model當作程序中惟一可信的數據來源。view始終是model的投影。。當model發生變化時,會自動反映到view上。
大多數的數據綁定都是單向的,當咱們的model和view修改後要去提醒另一個的話,就必須使用ajax之類的,好比jquery還要手動的同步,這樣子的話,增長了沒必要要的麻煩。
d.依賴注入:java
2.依賴注入 的詳解node
回顧下spring中的ioc 控制反轉:jquery
控制反轉(Inversion of Control,英文縮寫爲IoC)是一個重要的面向對象編程的法則來削減計算機程序的耦合問題,也是輕量級的Spring框架的核心。 控制反轉通常分爲兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)。依賴注入應用比較普遍。git
我的理解:就是原本須要你在程序設計時,建立的某些對象,交給spring來管理,當你須要某個時候須要某個對象的時候spring在給你,這樣子對象的生命週期之類的就由spring來維護了。angularjs
var A = function () {
this.getName = function () {
return '張三';
}
}github
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代碼
1 <div ng-controller="cartController" class="container"> 2 <table class="table" ng-show="cart.length"> 3 <thead> 4 <tr> 5 <th>產品編號</th> 6 <th>產品名字</th> 7 <th>購買數量</th> 8 <th>產品單價</th> 9 <th>產品總價</th> 10 <th>操做</th> 11 </tr> 12 </thead> 13 <tbody> 14 <tr ng-repeat="item in cart"> 15 <td>{{item.id}}</td> 16 <td>{{item.name}}</td> 17 <td> 18 <button type="button" ng-click="reduce(item.id)" class="btn tn-primary">-</button> 19 <input type="text" value="{{item.quantity}}" ng-model="item.quantity" > 20 <button type="button" ng-click="add(item.id)" class="btn tn-primary">+</button> 21 </td> 22 <td>{{item.price}}</td> 23 <td>{{item.price * item.quantity}}</td> 24 <td> 25 <button type="button" ng-click="remove(item.id)" class="btn btn-danger">移除</button> 26 </td> 27 </tr> 28 <tr> 29 <td> 30 總購買價 31 </td> 32 <td> 33 {{totalPrice()}} 34 </td> 35 <td> 36 總購買數量 37 </td> 38 <td> 39 {{totalQuantity()}} 40 </td> 41 <td colspan="2"> 42 <button type="button" ng-click="cart = {}" class="btn btn-danger">清空購物車</button> 43 </td> 44 </tr> 45 </tbody> 46 </table> 47 48 <p ng-show="!cart.length">您的購物車爲空</p> 49 </div>
1 var cartController = function ($scope) { 2 3 $scope.cart = [ 4 { 5 id: 1000, 6 name: 'iphone5s', 7 quantity: 3, 8 price: 4300 9 }, 10 { 11 id: 3300, 12 name: 'iphone5', 13 quantity: 30, 14 price: 3300 15 }, 16 { 17 id: 232, 18 name: 'imac', 19 quantity: 4, 20 price: 23000 21 }, 22 { 23 id: 1400, 24 name: 'ipad', 25 quantity: 5, 26 price: 6900 27 } 28 ]; 29 30 31 /** 32 * 計算購物總價 33 */ 34 $scope.totalPrice = function () { 35 var total = 0; 36 angular.forEach($scope.cart, function (item) { 37 total += item.quantity * item.price; 38 }) 39 return total; 40 } 41 42 /** 43 * 計算總購買數 44 */ 45 $scope.totalQuantity = function () { 46 var total = 0; 47 angular.forEach($scope.cart, function (item) { 48 total += parseInt(item.quantity); 49 }) 50 return total; 51 } 52 53 54 /** 55 * 找一個元素的索引 56 */ 57 var findIndex = function (id) { 58 var index = -1; 59 60 angular.forEach($scope.cart, function (item, key) { 61 if (item.id === id) { 62 index = key; 63 return; 64 } 65 }); 66 67 return index; 68 } 69 70 71 /** 72 * 爲某個產品添加一個數量 73 */ 74 $scope.add = function (id) { 75 var index = findIndex(id); 76 77 if (index !== -1) { 78 ++$scope.cart[index].quantity; 79 } 80 } 81 82 83 /** 84 * 爲某個產品減小一個數量 85 */ 86 $scope.reduce = function (id) { 87 var index = findIndex(id); 88 89 if (index !== -1) { 90 var item = $scope.cart[index]; 91 if(item.quantity > 1){ 92 --item.quantity; 93 }else{ 94 var returnKey = confirm('是否從購物車內刪除該產品!'); 95 if(returnKey){ 96 $scope.remove(id); 97 } 98 } 99 100 } 101 } 102 103 /** 104 * 移除一項 105 */ 106 $scope.remove = function (id) { 107 108 109 var index = findIndex(id); 110 // 若是找到了那個item 111 if (index !== -1) { 112 $scope.cart.splice(index, 1); 113 } 114 115 // 自動作髒檢查 116 } 117 118 // 監聽數量 若是小於 1 則讓用戶判斷是否要刪除產品 119 $scope.$watch('cart',function(newValue,oldValue){ 120 121 angular.forEach(newValue,function(item,key){ 122 if(item.quantity < 1){ 123 var returnKey = confirm('是否從購物車內刪除該產品!'); 124 if(returnKey){ 125 $scope.remove(item.id); 126 }else{ 127 item.quantity = oldValue[key].quantity; 128 } 129 } 130 }) 131 },true);
//若是這個方式和上邊的reduce同時執行的話,特別是reduce爲0的時候, 先執行reduce方法,remove以後,執行這個函數的時候,就已經找不到那個cart中對應的值了,因此confirm不會重複彈出。 132 133 134 135 }
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 [1,2,3,4,5,6,7]; }); // 自定義服務 $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"> <!--[1,2,3,4,5]--> <p>{{[1,2,3,4,5,6,7] | limitTo:5}}</p> <!--[3,4,5,6,7]--> <p>{{[1,2,3,4,5,6,7] | limitTo:-5}}</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')(3000); var jsonString = $filter('json')($scope.data); console.log(jsonString); console.log($scope.data); $scope.checkName = function(obj){ if(obj.py.indexOf('h') === -1) 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: '20', city: '上海' }, { name: '李四', age: '30', city: '北京' } ]; }); $filterProvider.register('filterAge', function () { return function (obj) { var newObj = []; angular.forEach(obj, function (o) { if (o.age > 20) { 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')([1, 2, 3, 4, 5])); }]); 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>{{1+1}}</p> <p ng-bind="1+1">2</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>1212</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"> <!-- 1. div 轉換爲dom結構 2. 默認的優先級爲0,哪一個先定義哪一個先使用 --> <div ng-repeat="user in users" custom-tags="" custom-tags2> </div> </div> </div>
var i = 0; 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:10, name:'張三' }, { id:20, 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:-1 } }) .directive('customTags3', function () { return { restrict: 'ECAM', template:'<div>3</div>', replace: true, priority: 0, // 小於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>在獲取數組 [255, 251, 200] 值時使用過濾器:</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(16); } }); app.filter('myFormat',['hexafy', function(hexafy) { return function(x) { return hexafy.myFunc(x); }; }]); app.controller('myCtrl', function($scope) { $scope.counts = [255, 251, 200]; }); </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發射的。