Angular 筆記
Angularjs 中 ui-sref 和 $state.go 如何傳遞參數
ng-repeat
[
[{},{}],
[{},{}],
[{},{}]
]
<tbody ng-repeat="t in vm.detailData track by $index" style="border:0">
<tr ng-repeat="i in t track by $index">
<td rowspan="{{i.length}}" ng-show="($index) % i.length == 0">{{i.date}}</td>
<td>{{i.platform}}</td>
</tr>
</tbody>
$apply()與 $digest()以及$Watch()
$watch 隊列?
每綁定UI,就往watch隊列里插入一條$watch, $watch監視model變化
$digest 循環?
包含兩個循環,一個循環evalAsync隊列,一個循環$watch隊列;
dirty-checking(臟檢測)?
$digest循環一遍所有$watch,會再循環一次確認無改變;超過10次會拋出異常,防止無限循環;
$apply ?
事件綁定:ng-click=fn() 相當于$scope.$apply(function(){fn)}) // fn() 被自動傳遞給$apply()包裹一層;$apply() 默認調用 $rootScope.$digest()
雙向綁定:ng-model="foo"的輸入框,然后你敲一個f,事件就會這樣調用$apply("foo = 'f';")
=>start
- 游覽器接受一個angular支持的事件 =>
- 調用$apply =>
- 進入angular 上下文 =>
- 執行$digest循環 =>
- 再$digest(無變化) =>
- 回到游覽器上下文,更新dom
<= end
ng-repeat高級
遍歷數組:<li ng-repeat="item in array">{{item}}</li>
遍歷對象:<li ng-repeat="(key,value) in obj">{{key}} | {{value}}</li>
綁定$$haskKey:
給每個item綁定唯一ID,當數組發生變化時,ID不變!
<li ng-repeat="item in items track by $id(item)"></li>
過濾器:
對item的每個屬性進行模糊匹配
<li ng-repeat="item in items |filter: 25"></li>
綁定屬性過濾:
對item的某個屬性進行模糊匹配
<li ng-repeat="item in items |filter: 25 track by item.age"></li>
保存匹配結果:
把匹配到的結果另存到results數組變量,可供外部使用
<li ng-repeat="item in items |filter: 25 as results"></li>
保存針對某個屬性的過濾結果:
<li ng-repeat="item in items |filter: 25 as results track by item.age "></li>
路由傳參:
'Root.Offer.EventInfo': {
url: '/EventInfo/:id',
},
'Root.Finance_adv.InvoiceDetail': {
url: '/Invoice/Detail?id&READ',
},
ui-sref="Root.Offer.EventInfo({id:item.id})
ng-model
ngModelController中兩個管道數組 $formatters 和 $parsers
$formatters :將Model數據轉換為view視圖顯示的值
$parsers: 將交互控件的view值轉換為Model格式的數據
ngModelCtrl.$parsers.push(function(value) {…});
ngModelCtrl.$formatters.push(function(value) {...});
ng-class
ng-class="{true: 'active', false: 'inactive'}[isActive]" //isActive表達式為true,則 active,否則inactive
ng-class = “{‘selected': isSelected, 'car': isCar}" //當 isSelected = true 則增加selected class,
當isCar=true,則增加car class,
ng 原理分析:
臟檢測機制的低效
只要變過數據,至少要跑兩次臟檢測
模塊機制
$scope 對象
是一個js 的 POJO
有兩個特別的函數:$watch 、$digest
DI 實現原理
在使用模塊時無需require()引入,直接通過形參注入到函數所在作用域
js實現DI
angular DI:
ng筆記:
七、模版:
#模版內容:
三種方式:字符串;外部文件,script定義內部文件
ng-include src=“ ‘’ ”
ng-include=“ ‘’ ”
<script type="text/ng-template" id="tpl">here, {{ 1 + 1 }}</script>
<div ng-include src="'tpl'"></div>
渲染控制
節點控制
ng-style
ng-class
ng-show | ng-hide | ng-switch
ng-src
ng-href
數據綁定:
- ng-src src屬性
- ng-href href屬性
- ng-checked 選中狀態
- ng-selected 被選擇狀態
- ng-disabled 禁用狀態
- ng-multiple 多選狀態
- ng-readonly 只讀狀態
事件綁定 (事件對象 $event $event.target)
- ng-change
- ng-click
- ng-dblclick
- ng-mousedown
- ng-mouseenter
- ng-mouseleave
- ng-mousemove
- ng-mouseover
- ng-mouseup
- ng-submit
表單控件
from 動態類:
- ng-valid 當表單驗證通過時的設置
- ng-invalid 當表單驗證失敗時的設置
- ng-pristine 表單的未被動之前擁有
- ng-dirty 表單被動過之后擁有
form 對象的屬性有:
- $pristine 表單是否未被動過
- $dirty 表單是否被動過
- $valid 表單是否驗證通過
- $invalid 表單是否驗證失敗
- $error 表單的驗證錯誤
input 相關可用屬性為:
- name 名字
- ng-model 綁定的數據
- required 是否必填
- ng-required 是否必填
- ng-minlength 最小長度
- ng-maxlength 最大長度
- ng-pattern 匹配模式
- ng-change 值變化時的回調
- input type="number" 多了 number 錯誤類型,多了 max , min 屬性。
- input type="url" 多了 url 錯誤類型。
- input type="email" 多了 email 錯誤類型。
- checkbox 選中ng-true-value="AA" 不選中ng-false-value="BB"
- radio value=“aa”
- select ng-options [數組、對象]
八、過濾器
內置過濾器
1. currency (貨幣處理) 人民幣:{{num | currency : ‘¥’}};默認是美元
2. date (日期格式化) {{date | date : 'yyyy-MM-dd hh:mm:ss EEEE'}}
y M d h m s E 表示 年 月 日 時 分 秒 星期,描述性字符串:“shortTime”將會把時間格式為12:05 pm
3. filter(匹配子串)
$scope.childrenArray = [{name:'shitou',age:6},{name:'tiantian',age:5}];
$scope.func = function(e){return e.age>4;}
{{ childrenArray | filter : 'a' }} //匹配屬性值中含有a的
{{ childrenArray | filter : {name : 'i'} }} //參數是對象,匹配name屬性中含有i的
{{childrenArray | filter : func }} //參數是函數,指定返回age>4的
4. json(格式化json對象) 格式化為json字符串,和JSON.stringify()一樣
5. limitTo(限制數組長度或字符串長度) {{ childrenArray | limitTo : 2 }} //將會顯示數組中的前兩項
6. lowercase(小寫)
7. uppercase(大寫)
8. number(格式化數字) //默認加上千位123,456,789。接收參數指定保留小數位 {{ num | number : 2 }}
9. orderBy(排序)
參數為字符串,表示以該屬性名稱進行排序。
參數為函數,定義排序屬性。
參數為數組,表示依次按數組中的屬性值進行排序(若按第一項比較的值相等,再按第二項比較)
<div>{{ childrenArray | orderBy : 'age' }}</div> //按age屬性值進行排序,若是-age,則倒序
<div>{{ childrenArray | orderBy : orderFunc }}</div> //按照函數的返回值進行排序
<div>{{ childrenArray | orderBy : ['age','name'] }}</div> //如果age相同,按照name進行排序
自定義過濾器
使用module的filter方法,返回一個函數,該函數接收輸入值,并返回處理后的結果。
比如我需要一個過濾器,它可以返回一個數組中下標為奇數的元素,代碼如下:
app.filter('odditems',function(){
return function(inputArray){
var array = [];
for(var i=0;i<inputArray.length;i++){
if(i%2!==0){
array.push(inputArray[i]);
}
}
return array;
}
});
處理邏輯就寫在內部的閉包函數中。你也可以讓自己的過濾器接收參數,參數就定義在return的那個函數中,作為第二個參數,或者更多個參數也可以。
九、路由
十、定義模版變量標識符
十一、Ajax
$http
$q
十二、工具函數
angular.bind()
angular.copy()
angular.extend()
空函數: angular.noop()
大小寫轉換: angular.lowercase()和 angular.uppercase()
JSON轉換: angular.fromJson()和 angular.toJson()
遍歷: angular.forEach(),支持列表和對象
類型判定
- angular.isArray
- angular.isDate
- angular.isDefined
- angular.isElement
- angular.isFunction
- angular.isNumber
- angular.isObject
- angular.isString
- angular.isUndefined
十三、其它服務
日志 $log
緩存 $cacheFactory
計數器 $timeout $timeout.cancel()取消
表達式函數化 $parse
模版單獨使用 $compile
十四、自定義模塊與服務
ng模塊(默認模塊):提供$http,$q等服務
模塊提供包括:服務、指令、過濾器、及其他配置信息等機制
使用時,模塊需要顯示聲明依賴,服務可以通過ng自動注入
自定義服務:
provider對象 :被“注入控制器”使用的一個對象 注入機制通過provider.$get(),把得到的東西作為參數進行相關調用
eg:把得到的服務作為一個controller 的參數
底層方法:
$provider.provider(‘pp’, function(){this.$get = ()=>{‘haha’:’1234’}})
//定義一個叫pp的服務,pp服務也就是pp這個provider的get()返回的東西
factory 返回object
$provider.factory(‘pp’, function(){return {}})
app.factory('PP', function(){return {'abc': '123'}});
service 可以是數字、字符串
app.service('PP', function(){this.abc = '123';});
provider
1. 為應用提供通用的服務,形式可以是常量或對象
2. 便于模塊化
3. 便于單元測試
provider可寫成
$provide.provider('age', {
start: 10,
$get: function() {
return this.start + 2;
}
});
//或
$provide.provider('age', function($filterProvider){
this.start = 10;
this.$get = function() {
return this.start + 2;
};
});
//調用:
app.controller('MainCtrl', function($scope, age) {
$scope.age = age; //12
});
其原理是通過實現$get方法來在應用中注入單例,使用的時候拿到的age就是$get執行后的結果
factory可以寫成
$provide.factory('myDate', function(){
return new Date();
});
service可寫成
$provide.service('myDate', Date);
value & constant
區別一:****value****可以被修改,****constant****一旦聲明無法被修改
1 $provide.decorator('pageCount', function($delegate) {
2 return $delegate + 1;
3 });
decorator可以用來修改(修飾)已定義的provider們,除了constant~
區別二:****value****不可在****config配置函數里注入,****constant****可以
1 myApp.config(function(pageCount){
2 //可以得到constant定義的'pageCount'
3 });
十五、附加模塊 ngResource
十六、與其它框架混用
ng 最忌諱修改 DOM 結構——應該使用 ng 的模板機制進行數據綁定,以此來控制 DOM 結構,而不是直接操作。
數據使用哪個框架來控制都是沒問題的,如有必要使用 $scope.$digest() 來通知 ng 一下即可
十七、自定義過濾器
filter 就是一個函數,雖然定義在module下,但無任何上下文關聯的能力
app.filter('map', function(){
var filter = function(input){return input + '...'; };
return filter;
});
使用:{{ a|map}}
傳參:{{ a|map:map_value:'>>':'(no)' }}
十八、自定義指令
指令返回一個對象 return{};返回return fn的話,fn將作為link函數使用
directive的執行過程:
瀏覽器解析html字符串得到 DOM 結構
ng 引入,把 DOM 結構扔給 $compile 函數處理:
找出 DOM 結構中有變量占位符
匹配找出 DOM 中包含的所有指令引用
把指令關聯到 DOM
關聯到 DOM 的多個指令按權重排列
執行指令中的 compile 函數(改變 DOM 結構,返回 link 函數)
得到的所有 link 函數組成一個列表作為 $compile 函數的返回
執行 link 函數(連接模板的 scope)。
瀏覽器把 HTML 字符串解析成 DOM 結構。
ng 把 DOM 結構給 $compile ,返回一個 link 函數。
傳入具體的 scope 調用這個 link 函數。
得到處理后的 DOM ,這個 DOM 處理了指令,連接了數據。
一個完整指令返回一個對象,包含compile、link、restrict等屬性;
如果指令返回一個函數fn,則這個fn會作為compile的返回值,也即作為link函數使用;
指令包含的屬性
- name
- priority
- terminal
- scope
- controller
- require
- restrict
- template
- templateUrl
- replace
- transclude
- compile
- link
app.directive('color', function(){
var link = function($scope, $element, $attrs){
$scope.$watch($attrs.color, function(new_v){
$element.css('color', new_v);
});
}
return link;
});
compile的細節
基本形式
let link = $compile(‘<div></div>’); //返回link函數
let node = link($scope, cloneAttachFN);// cloneAttchFn表示是否復制原始節點以及對復制節點需要做的處理
注意:這里不能做數據綁定;因為{{ }}在 $compile 中已被處理過,生成了相關函數;后面執行 link 就是執行了 $compile 生成的這些函數。如果你的文本沒有數據變量的引用,那修改是會有效果的。
link 函數是由 compile 函數返回的;應該把改變 DOM 結構的邏輯放在 compile 函數中做。
$compile另外兩個參數:
$compile(element, transclude, maxPriority);
$compile
解析html模板
返回兩個函數pre-link和post-link
先執行pre-link,從父節點到子節點遍歷,在這個階段,進行一些初始化數據的處理。
第二執行的是post-link,即link函數,從子節點到父節點遍歷,在這個階段,DOM節點已經穩定下來
$parse 服務
解析表達式,將一個表達式轉換為一個函數
var getter = $parse('user.name');
var setter = getter.assign;
setter(scope, 'new name');
getter(context, locals) // 傳入作用域,返回值 context含有你要解析語句中的表達式,通常為一個scope對象
setter(scope,'new name') // 修改映射在scope上的屬性的值為‘new value’
$eval()方法
基于$parse, 作為scope的方法使用;scope.$eval('a+b'); 而這個里的a,b是來自 scope = {a: 2, b:3};
transclude
transclude:true //在指令中說明需要嵌入
ng-transclude //在模版中說明要嵌入的位置
取出自定義指令中的內容(就是寫在指令里面的子元素),以正確的作用域解析它,然后再放回指令模板中標記的位置(通常是ng-transclude標記的地方),
注入服務
服務可以定義在任意模塊,注入服務時需要引入所在的模塊依賴;
link
link函數的$attrs 參數 : 指令元素的屬性合集;
$attrs.$observe()方法: 監聽屬性變化,觸發一個回調函數
$scope 的屬性
$id: "002" scope唯一標示
$root: Scope 根scope
$parent: null 父scope
$$childHead: null 第一個子scope
$$childTail: null 最后一個子scope
$$prevSibling: null 上一個兄弟scope
$$nextSibling: null 下一個兄弟scope
$$phase: null
$$destroyed: false
$$isolateBindings: Object
$$listenerCount: Object
$$postDigestQueue: Array[0]
$$watchers: Array[1]
$$asyncQueue: Array[0]
////發布訂閱事件模型 可在各級controller內傳遞event和data
$$listeners: Object 在scope上注冊事件監聽器
//原型繼承.proto
$on(evt,fn(args)) 監聽處理(名為evt,監聽器為fn)
$emit(evt,args) 發送evt事件,冒泡;在當前scope及所有$parents上觸發
$broadcast(eat,args) 發送事件eat,捕獲;在當前scope及其所有children上觸發
"$new",
"$watch",
"$watchCollection",
"$digest",
"$destroy",
"$eval",
"$evalAsync",
"$$postDigest",
"$apply",
constructor
指令的幾種參數
內部參數 //描述指令或DOM本身特性的內部參數
restrict:String, E(元素) A(屬性,默認值)C(類名) M(注釋)
priority: Number, 指令執行優先級
template: String, 指令鏈接DOM模板,例如“<h1>{{head}}</h1>”
templateUrl:String, DOM模板路徑
replace: Boolean, 指令鏈接模板是否替換原有元素
對外參數scope // scope是指令與外界作用域通訊的橋梁
scope:Boolean or Object 隔離指令與所在控制器間的作用域、隔離指令與指令間的作用域
false 共享父域(默認值);
true 繼承父域且新建獨立作用;
指令未申明scope.data時, 在指令中可監聽父域data。父域變更,指令數據也會變更;但一旦指令中input變更了,指令獨立scope也會自動綁定
指令已聲明scope.data時,在指令中監聽父域data無效。但可通過scope.$parent監聽父域
{} 不繼承父域且新建獨立作用域()
對外參數require // require是指令與指令之間通訊的橋梁
require: String or Array 通過require參數,指令可以獲得外部其他指令的控制器,從而達到交換數據、事件分發的目的
require: '^teacher1', 如果require為String,ctrl為對象,如果require是數組,ctrl為數組。
link: function ($scope, $element, $attrs, ctrl) { //ctrl參數指向teacher1指令的控制器}
?策略 尋找指令名稱。如果找不到,link第4個參數為null。 假如無“?”則報錯。
^ 策略 在自身指令尋找指令名稱,同時向上父元素尋找。 假如沒有“^”則僅在自身尋找。
行為參數link與controller //描述指令本身行為的行為參數 先controller,后link
controller: 控制器函數;定義指令內部作用域的行為
link 鏈接函數; 定義指令元素的操作行為
- 分析指令,加載模板,形成DOM模板樹
- 執行link,設置DOM各個行為;從最底部指令開始依次執行指令的link函數(適合dom操作,性能開銷最小,如鼠標操作或觸控事件分發綁定、樣式Class設置、增刪改元素等等)
- 數據綁定(最后scope綁上DOM)
$watch()
scope對象的方法;推薦在指令的link函數中使用;
可以監測expression和函數的變化,它使用$parse將angular expression解析為一個函數,
這個函數會在angular的每個臟值檢查循環中被調用。 $observe()
指令中link函數中實例屬性即(iAttr)的方法。 只可以在指令的link函數中使用。 只監測angular expression的變化
異同:
$rootscope之所以被稱為"root"的原因就是他是所有scope的祖先,$rootscope是在angular啟動流程中建立的(上上期講過),而被注入到controller中的$scope則是在視圖創建的時候通過父輩的$scope.$new制造出來的,在視圖銷毀的時候,$scope會被跟著銷毀。$scope是鏈接視圖和controller的重要手段,controller則是可以與服務進行鏈接,將服務提供的功能進行組合,然后丟給$scope,$scope則將這些傳遞給視圖,讓它顯示給用戶。如果將一個$scope比作一個人的話,那么他的功能有:生育功能($new)、進食功能($watch)、消化功能($digest)、執行功能($apply)、交流功能($on、$emit、$broadcast)、死亡功能($destory)。
compile & link
只使用了一個link函數,那么ng會把這個函數當成post-link來處理
compile函數: 返回pre-link post-link
執行順序: 先compile 再pre-link 再post-link
compile與pre-link函數: 順序執行
post-link函數: 反序執行
module
- _invokeQueue
:
Array[4]
_runBlocks
:
Array[0]
animation
:
()config
:
()constant
:
()controller
:
()directive
:
()factory
:
()filter
:
()name
:
"PonyDeli"
provider
:
()requires
:
Array[0]
run
:
(block)service
:
()value
:
()
$log 服務
debug()error()info()log()warn()