从零学前端第十四讲:AngularJs进阶-作用域和控制器
修真院Web工程師零基礎(chǔ)全能課
本節(jié)課內(nèi)容
AngularJs進(jìn)階-作用域和控制器
主講人介紹
沁修,葡萄藤技術(shù)總監(jiān)
項(xiàng)目經(jīng)驗(yàn)豐富,擅長(zhǎng)H5移動(dòng)項(xiàng)目開(kāi)發(fā)。
專(zhuān)注技術(shù)選型、底層開(kāi)發(fā)、最佳代碼實(shí)踐規(guī)范總結(jié)與推廣。
直播錄屏版
傳送門(mén):https://v.qq.com/x/page/t0782...
文字解析版
什么是scope作用域?
scope作用域是一個(gè)指向應(yīng)用model的對(duì)象object,也是表達(dá)式的執(zhí)行環(huán)境。
作用域有層次結(jié)構(gòu),有根作用域,有很多子作用域,根據(jù)位置不同而不同。
作用域還能監(jiān)控表達(dá)式,傳遞事件。
比如在html當(dāng)中,我們都會(huì)定義一個(gè)ng-app指令,那么隨之而來(lái)就是一個(gè)作用域產(chǎn)生了。
不過(guò)由ng-app生成的作用域比較特殊,它是一個(gè)根作用域$rootscope,也就是其他所有scope的頂層。
除此之外,還有很多指令都會(huì)產(chǎn)生一個(gè)作用域,比如ng-controller, ng-repeat等。這些作用域都擁有自己的繼承上下文,并且根作用域都是rootscope。
在我們生成一個(gè)作用域之后,$scope對(duì)象就代表了這個(gè)作用域的數(shù)據(jù)。
我們可以在$scope內(nèi)定義各種數(shù)據(jù),之后可以直接在html中以雙花括號(hào)的表達(dá)式的方式來(lái)讓html得到這個(gè)變量。
scope的用法?
在正式開(kāi)始接觸scope之前我們?cè)賮?lái)熟悉一下js的全局變量和局部變量:
var foo = "foo";
function bar() {
var foo = "bar";
console.log(foo);
}
bar();
console.log(foo);
這里說(shuō)明,全局變量可以在方法內(nèi)引入,而局部變量只能在定義的方法內(nèi)使用,angular作用域跟變量性質(zhì)相似。
angularjs中的全局作用域:
var myApp = angular.module('myApp', []);
/*
- run方法用于初始化全局的數(shù)據(jù),僅對(duì)全局作用域起作用。
- 這里的run方法只會(huì)在angular啟動(dòng)的時(shí)候運(yùn)行一次。
*/
myApp.run(function($rootScope){
$rootScope.version = 2.0;
});
全局作用域是所有controller的scope的橋梁。
rootscope定義的值,可以在各個(gè)controller中使用。
經(jīng)常用于需要在多個(gè)頁(yè)面場(chǎng)景中的數(shù)據(jù)就可以定義到全局作用域上。
angularjs中的局部作用域:
myApp.controller('homeCtrl', function($scope){
$scope.person = {
name: 'max'
}
})
myApp.controller('productCtrl',function($scope,$rootScope){
console.log($scope.person.name);//undefined
console.log($rootScope.version) //2.0
})
前面我們已經(jīng)說(shuō)過(guò),每一個(gè)angular應(yīng)用有且只有一個(gè)root scope,但可以擁有多個(gè)child scope。
因?yàn)橐恍ヾirective會(huì)創(chuàng)建新的child scope,當(dāng)新的scope被創(chuàng)建后,他們將作為一個(gè)child scope,加入到parent scope中。
這樣,創(chuàng)建了一個(gè)與它們附屬的DOM相似的樹(shù)結(jié)構(gòu)。
當(dāng)angular在html中對(duì){{person}}求值時(shí),它首先查看與當(dāng)前元素關(guān)聯(lián)的scope的person屬性。
如果沒(méi)有找到對(duì)應(yīng)的屬性,它將會(huì)一直向上搜索parent scope,直到到達(dá)root scope。
在javascript中,這個(gè)行為被稱(chēng)為“原型繼承”,child scope典型地繼承自它們的parent。
$scope特點(diǎn)?
提供了$watch()方法,用于監(jiān)聽(tīng)模型的變化
提供了$apply()方法,用于傳播模型的變化
$watch()監(jiān)聽(tīng)模型變化,當(dāng)模型發(fā)生變化,它會(huì)給你提示。
表達(dá)式:
$watch(watchExpression, listener, objectEquality);?
watchExpression:監(jiān)聽(tīng)的對(duì)象,比如一個(gè)angular表達(dá)式如’scope.person’。
listener:當(dāng)watchExpression變化時(shí)會(huì)被調(diào)用的函數(shù)或者表達(dá)式,它接收3個(gè)參數(shù):
newValue(新值), oldValue(舊值), scope(作用域的引用)。
objectEquality:是否深度監(jiān)聽(tīng),如果設(shè)置為true,它告訴Angular檢查所監(jiān)控的對(duì)象中每一個(gè)屬性的變化.。
如果你希望監(jiān)控?cái)?shù)組的個(gè)別元素或者對(duì)象的屬性而不是一個(gè)普通的值, 那么你應(yīng)該使用它。
$scope.name = 'hello';
$scope.$watch('name',function(newValue, oldValue, scope){
console.log(newValue);
console.log(oldValue);
});
$timeout(function(){
$scope.name = "world";
},1000);
$apply()用于傳播模型的變化。
AngularJS 外部的控制器(DOM 事件、外部的回調(diào)函數(shù)如jQuery等)調(diào)用了AngularJS 函數(shù)之后,就需要調(diào)用$apply。
myApp.controller('homeCtrl', function($scope){
vm.name = 'hello';
setTimeout(function () {
vm.name = "world";
}, 2000);
})
預(yù)期的應(yīng)該是先顯示hello, 兩秒后改為world。
但事實(shí)是我們發(fā)現(xiàn)它不會(huì)自動(dòng)變化,因?yàn)檎{(diào)研了外部的事件,所以需要用$apply方法就可以了:
myApp.controller('homeCtrl', function($scope){
vm.name = 'hello';
setTimeout(function () {
$scope.$apply(function () {
vm.name = "world";
});
}, 2000);
})
$scope的生命周期?
創(chuàng)建?creation
↓
注冊(cè)監(jiān)視器?watcher registration
↓
模型變化?model mutation
↓
變化檢測(cè)?mutation observation
↓
作用域銷(xiāo)毀?scope destruction
瀏覽器正常的事件流中,當(dāng)瀏覽器接收到事件后,它會(huì)執(zhí)行一個(gè)相應(yīng)的javascript回調(diào)。
一旦回調(diào)函數(shù)執(zhí)行完畢后,瀏覽器將會(huì)重繪DOM,并返回到繼續(xù)等待事件的狀態(tài)。
1.在應(yīng)用啟動(dòng)的過(guò)程中,會(huì)創(chuàng)建rootscope,而后在模板的鏈接過(guò)程中,一些directive會(huì)創(chuàng)建新的child scope。
2.directive在scope中注冊(cè)$watch,這些watch會(huì)用來(lái)向DOM傳播model的值。
3.更新模型狀態(tài)必須是在$apply方法中才可以被觀察到,不過(guò)angular框架是封裝了這個(gè)方法過(guò)程的。
我們通常無(wú)需擔(dān)心,除非是之前提到過(guò)的,angular以外的一些方法事件在觸發(fā)后,不能正常調(diào)用$apply才需要手動(dòng)去添加這個(gè)方法。
4.$apply方法結(jié)束后,angular會(huì)在根作用域執(zhí)行一個(gè)$digest周期并且擴(kuò)散到所有子作用域。
scope檢查所有$watch監(jiān)聽(tīng)的表達(dá)式,將現(xiàn)在的值與舊的值作比較。
這個(gè)過(guò)程會(huì)檢查模型狀態(tài)是否改變以及更新。
5.銷(xiāo)毀作用域,當(dāng)不在需要子作用域的時(shí)候,就會(huì)被銷(xiāo)毀掉。
總結(jié)$scope?
1、提供了觀察者可以監(jiān)聽(tīng)數(shù)據(jù)模型的變化
2、可以將數(shù)據(jù)模型的變化通知給整個(gè) App
3、可以進(jìn)行嵌套,隔離業(yè)務(wù)功能和數(shù)據(jù)
4、給表達(dá)式提供上下文執(zhí)行環(huán)境
在scope之后我們又來(lái)看看和它關(guān)系非常緊密的控制器controller。。。
什么是控制器?
從作用上來(lái)講,controller主要是對(duì)視圖中的數(shù)據(jù)和事件函數(shù)進(jìn)行掛載,同時(shí)處理一些業(yè)務(wù)的地方。
從功能上來(lái)講,在angularjs中,controller是一個(gè)js函數(shù),用來(lái)擴(kuò)展angular的子scope的實(shí)例。
因此它可以用來(lái)設(shè)置scope對(duì)象的初始狀態(tài),并且增加一些屬性行為到scope中。
控制器使用?
在模板中聲明控制器
<div ng-controller="myController">...</div>
控制器實(shí)際上就是一個(gè)js的構(gòu)造函數(shù):
//控制器類(lèi)定義
var myControllerClass = function($scope){
//模型屬性定義
$scope.text = "...";
//模型方法定義
$scope.do = function(){...};
};
//在模塊中注冊(cè)控制器
angular.module('someModule',[])
.controller("myController",myControllerClass);
控制器構(gòu)造函數(shù)僅在AngularJS對(duì)HTML文檔進(jìn)行編譯時(shí)被執(zhí)行一次。
一旦控制器創(chuàng)建完畢,就意味著scope對(duì)象上的業(yè)務(wù)模型構(gòu)造完畢,此后就不再需要控制器了,因?yàn)閟cope對(duì)象接管了。
控制器和scope?
<html ng-app=“myApp">
<body ng-init=“foo={name:’hello'}”>
<div ng-controller=“myCtrl"></div>
</body>
</html>
對(duì)scope的影響是什么樣的呢?
$rootScope: {
foo: {name: ‘hello'}
}
scope: {
prototype: $rootScope,
bar: ...
}
可以看到ng-app指令創(chuàng)建了$rootScope對(duì)象,這個(gè)時(shí)候它還是一個(gè)空對(duì)象。
body元素對(duì)應(yīng)的scope對(duì)象還是$rootScope,ng-init指令將foo對(duì)象掛到了$rootScope上
div元素又通過(guò)ng-controller指令創(chuàng)建了一個(gè)新的scope對(duì)象,這個(gè)對(duì)象的原型是$rootScope
因?yàn)槔^承關(guān)系,如果在scope中引用foo會(huì)指向$rootScope.foo
注意不要在controller中做的事情:
1.DOM操作
2.表單輸入的格式化,用form controls
3.輸出內(nèi)容的格式化和過(guò)濾,用filter
4.控制器之間的數(shù)據(jù)共享,另外定義services服務(wù)來(lái)處理
以上就是上節(jié)課的內(nèi)容解析啦
總結(jié)
以上是生活随笔為你收集整理的从零学前端第十四讲:AngularJs进阶-作用域和控制器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQL Server遍历表的几种方法
- 下一篇: 2017年html5行业报告,云适配发布