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