Angular.Js之Scope作用域的學(xué)習(xí)教程
scope是什么?
大家都知道在AngularJS 中作用域是一個(gè)指向應(yīng)用模型的對(duì)象,它是表達(dá)式的執(zhí)行環(huán)境。作用域有層次結(jié)構(gòu),這個(gè)層次和相應(yīng)的 DOM 幾乎是一樣的。作用域能監(jiān)控表達(dá)式和傳遞事件。
在 HTML 代碼中,一旦一個(gè) ng-app 指令被定義,那么一個(gè)作用域就產(chǎn)生了,由 ng-app 所生成的作用域比較特殊,它是一個(gè)根作用域($rootScope),它是其他所有$Scope 的最頂層。
除了用 ng-app 指令可以產(chǎn)生一個(gè)作用域之外,其他的指令如 ng-controller,ng-repeat 等都會(huì)產(chǎn)生一個(gè)或者多個(gè)作用域。此外,還可以通過(guò) AngularJS 提供的創(chuàng)建作用域的工廠方法來(lái)創(chuàng)建一個(gè)作用域。這些作用域都擁有自己的繼承上下文,并且根作用域都為$rootScope。
在生成一個(gè)作用域之后,在編寫 AngularJS 代碼時(shí),$scope 對(duì)象就代表了這個(gè)作用域的數(shù)據(jù)實(shí)體,我們可以在$scope 內(nèi)定義各種數(shù)據(jù)類型,之后可以直接在 HTML 中以 {{變量名}} 方式來(lái)讓 HTML 訪問(wèn)到這個(gè)變量。
繼承作用域
AngularJS 在創(chuàng)建一個(gè)作用域時(shí),會(huì)檢索上下文,如果上下文中已經(jīng)存在一個(gè)作用域,那么這個(gè)新創(chuàng)建的作用域就會(huì)以 JavaScript 原型繼承機(jī)制繼承其父作用域的屬性和方法。
一些 AngularJS 指令會(huì)創(chuàng)建新的子作用域,并且進(jìn)行原型繼承: ng-repeat、ng-include、ng-switch、ng-view、ng-controller, 用 scope: true
和 transclude: true
創(chuàng)建的 directive。
以下 HTML 中定義了三個(gè)作用域,分別是由 ng-app 指令所創(chuàng)建的$rootScope,parentCtrl 和 childCtrl 所創(chuàng)建的子作用域,這其中 childCtrl 生成的作用域又是 parentCtrl 的子作用域。
示例一:作用域的繼承實(shí)例
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script type="text/javascript"> angular.module('app', []) .controller('parentCtrl', ['$scope', function($scope) { $scope.args= 'Nick DeveloperWorks'; }]) .controller('childCtrl', ['$scope', function($scope) { $scope.args= 'Nick DeveloperWorks for test'; }]); </script> <body ng-app="app"> <div ng-controller="parentCtrl"> <input ng-model="args"> <div ng-controller="childCtrl"> <input ng-model="args"> </div> </div> </body> </html>
繼承作用域符合 JavaScript 的原型繼承機(jī)制,這意味著如果我們?cè)谧幼饔糜蛑性L問(wèn)一個(gè)父作用域中定義的屬性,JavaScript 首先在子作用域中尋找該屬性,沒找到再?gòu)脑玩溕系母缸饔糜蛑袑ふ?,如果還沒找到會(huì)再往上一級(jí)原型鏈的父作用域?qū)ふ?。?AngularJS 中,作用域原型鏈的頂端是$rootScope,AnguarJS 將會(huì)尋找到$rootScope 為止,如果還是找不到,則會(huì)返回 undefined。
我們用實(shí)例代碼說(shuō)明下這個(gè)機(jī)制。首先,我們探討下對(duì)于原型數(shù)據(jù)類型的作用域繼承機(jī)制:
示例二:作用域繼承實(shí)例-原始類型數(shù)據(jù)繼承
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script type="text/javascript"> angular.module('app', []) .controller('parentCtrl', ['$scope', function($scope) { $scope.args = 'Nick DeveloperWorks'; }]) .controller('childCtrl', ['$scope', function($scope) { }]); </script> <body ng-app="app"> <div ng-controller="parentCtrl"> <input ng-model="args"> <div ng-controller="childCtrl"> <input ng-model="args"> </div> </div> </body> </html>
測(cè)試運(yùn)行結(jié)果:
第一個(gè)輸入框:
雖然在 childCtrl 中沒有定義具體的 args 屬性,但是因?yàn)?childCtrl 的作用域繼承自 parentCtrl 的作用域,因此,AngularJS 會(huì)找到父作用域中的 args 屬性并設(shè)置到輸入框中。而且,如果我們?cè)诘谝粋€(gè)輸入框中改變內(nèi)容,內(nèi)容將會(huì)同步的反應(yīng)到第二個(gè)輸入框。
第二個(gè)輸入框:
第二個(gè)輸入框的內(nèi)容從此將不再和第一個(gè)輸入框的內(nèi)容保持同步。在改變第二個(gè)輸入框的內(nèi)容時(shí),因?yàn)?HTML 代碼中 model 明確綁定在 childCtrl 的作用域中,因此 AngularJS 會(huì)為 childCtrl 生成一個(gè) args 原始類型屬性。這樣,根據(jù) AngularJS 作用域繼承原型機(jī)制,childCtrl 在自己的作用域找得到 args 這個(gè)屬性,從而也不再會(huì)去尋找 parentCtrl 的 args 屬性。從此,兩個(gè)輸入框的內(nèi)容所綁定的屬性已經(jīng)是兩份不同的實(shí)例,因此不會(huì)再保持同步。
現(xiàn)將代碼做如下修改,結(jié)合以上兩個(gè)場(chǎng)景,會(huì)出現(xiàn)怎樣的結(jié)果?
示例三:作用域繼承實(shí)例-對(duì)象數(shù)據(jù)繼承
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script type="text/javascript"> angular.module('app', []) .controller('parentCtrl', ['$scope', function($scope) { $scope.args = {}; $scope.args.content = 'Nick DeveloperWorks'; }]) .controller('childCtrl', ['$scope', function($scope) { }]); </script> <body ng-app="app"> <div ng-controller="parentCtrl"> <input ng-model="args.content"> <div ng-controller="childCtrl"> <input ng-model="args.content"> </div> </div> </body> </html>
測(cè)試結(jié)果是無(wú)論改變?nèi)魏我粋€(gè)輸入框的內(nèi)容,兩者的內(nèi)容始終同步。
根據(jù) AngularJS 的原型繼承機(jī)制,如果 ng-model 綁定的是一個(gè)對(duì)象數(shù)據(jù),那么 AngularJS 將不會(huì)為 childCtrl 創(chuàng)建一個(gè) args 的對(duì)象,自然也不會(huì)有 args.content
屬性。這樣,childCtrl 作用域中將始終不會(huì)存在 args.content
屬性,只能從父作用域中尋找,也即是兩個(gè)輸入框的的變化其實(shí)只是在改變 parentCtrl 作用域中的 args.content
屬性。因此,兩者的內(nèi)容始終保持同步。
我們?cè)倏匆粋€(gè)例子,分析結(jié)果如何。
示例四:作用域繼承實(shí)例-不再訪問(wèn)父作用域的數(shù)據(jù)對(duì)象。
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script type="text/javascript"> angular.module('app', []) .controller('parentCtrl', ['$scope', function($scope) { $scope.args = {}; $scope.args.content = 'Nick DeveloperWorks'; }]) .controller('childCtrl', ['$scope', function($scope) { $scope.args = {}; $scope.args.content = 'Nick DeveloperWorks for test'; }]); </script> <body ng-app="app"> <div ng-controller="parentCtrl"> <input ng-model="args.content"> <div ng-controller="childCtrl"> <input ng-model="args.content"> </div> </div> </body> </html>
測(cè)試結(jié)果是兩個(gè)輸入框的內(nèi)容永遠(yuǎn)不會(huì)同步。子作用域有實(shí)例數(shù)據(jù)對(duì)象,則不訪問(wèn)父作用域。
獨(dú)立作用域
獨(dú)立作用域是 AngularJS 中一個(gè)非常特殊的作用域,它只在 directive 中出現(xiàn)。在對(duì) directive 的定義中,我們添加上一個(gè) scope:{}
屬性,就為這個(gè) directive 創(chuàng)建出了一個(gè)隔離作用域。
示例5: directive 創(chuàng)建出一個(gè)孤立作用域
angular.module('isolate', []).directive("isolate", function () { return { scope : {}, }; })
獨(dú)立作用域最大的特點(diǎn)是不會(huì)原型繼承其父作用域,對(duì)外界的父作用域保持相對(duì)的獨(dú)立。因此,如果在定義了孤立作用域的 AngularJS directive 中想要訪問(wèn)其父作用域的屬性,則得到的值為 undefined。代碼如下:
示例六:獨(dú)立作用域的隔離性
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script type="text/javascript"> angular.module('app', []) .controller('ctrl', ['$scope', function($scope) { $scope.args = {}; }]) .directive("isolateDirective", function () { return { scope : {}, link : function($scope, $element, $attr) { console.log($scope.$args); //輸出 undefined } }; }); </script> <body ng-app="app"> <div ng-controller="ctrl"> <div isolate-directive></div> </div> </body> </html>
上面的代碼中通過(guò)在 directive 中聲明了 scope 屬性從而創(chuàng)建了一個(gè)作用域,其父作用域?yàn)?ctrl 所屬的作用域。但是,這個(gè)作用域是孤立的,因此,它訪問(wèn)不到父作用域的中的任何屬性。存在這樣設(shè)計(jì)機(jī)制的好處是:能夠創(chuàng)建出一些列可復(fù)用的 directive,這些 directive 不會(huì)相互在擁有的屬性值上產(chǎn)生串?dāng)_,也不會(huì)產(chǎn)生任何副作用。
AngularJS 獨(dú)立作用域的數(shù)據(jù)綁定
在繼承作用域中,我們可以選擇子作用域直接操作父作用域數(shù)據(jù)來(lái)實(shí)現(xiàn)父子作用域的通信,而在獨(dú)立作用域中,子作用域不能直接訪問(wèn)和修改父作用域的屬性和值。為了能夠使孤立作用域也能和外界通信,AngularJS 提供了三種方式用來(lái)打破獨(dú)立作用域“孤立”這一限制。
單向綁定(@ 或者 @attr)
這是 AngularJS 獨(dú)立作用域與外界父作用域進(jìn)行數(shù)據(jù)通信中最簡(jiǎn)單的一種,綁定的對(duì)象只能是父作用域中的字符串值,并且為單向只讀引用,無(wú)法對(duì)父作用域中的字符串值進(jìn)行修改,此外,這個(gè)字符串還必須在父作用域的 HTML 節(jié)點(diǎn)中以 attr(屬性)的方式聲明。
使用這種綁定方式時(shí),需要在 directive 的 scope 屬性中明確指定引用父作用域中的 HTML 字符串屬性,否則會(huì)拋異常。示例代碼如下:
實(shí)例七: 單向綁定示例
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script> angular.module('isolateScope', []) .directive("isolateDirective", function () { return { replace : true, template: '<button>{{isolates}}</button>', scope : { isolates : '@', }, link : function($scope, $element, $attr) { $scope.isolates = "DeveloperWorks";//無(wú)效 } }; }) .controller("ctrl", function ($scope) { $scope.btns = 'NICK'; }); </script> <body ng-app="isolateScope" > <div ng-controller="ctrl"> <button>{{btns}}</button> <div isolate-directive isolates="{{btns}}"></div> </div> </body> </html>
上面的代碼,通過(guò)在 directive 中聲明了 scope:{isolates:'@'}
使得 directive 擁有了父作用域中 data-isolates (isolates為自定義屬性,不加data也可以,但建議加上data)這個(gè) HTML 屬性所擁有的值,這個(gè)值在控制器 ctrl 中被賦值為'nick'。所以,代碼的運(yùn)行結(jié)果是頁(yè)面上有兩個(gè)名為 nick的按鈕。
我們還注意到 link 函數(shù)中對(duì) isolates 進(jìn)行了修改,但是最終不會(huì)在運(yùn)行結(jié)果中體現(xiàn)。這是因?yàn)?isolates 始終綁定為父作用域中的 btns 字符串,如果父作用域中的 btns 不改變,那么在孤立作用域中無(wú)論怎么修改 isolates 都不會(huì)起作用。
通過(guò)這種形式的綁定,孤立作用域?qū)⒂心芰υL問(wèn)到父作用域中的函數(shù)對(duì)象,從而能夠執(zhí)行父作用域中的函數(shù)來(lái)獲取某些結(jié)果。這種方式的綁定跟單向綁定一樣,只能以只讀的方式訪問(wèn)父作用函數(shù),并且這個(gè)函數(shù)的定義必須寫在父作用域 HTML 中的 attr(屬性)節(jié)點(diǎn)上。
這種方式的綁定雖然無(wú)法修改父作用域的 attr 所設(shè)定的函數(shù)對(duì)象,但是卻可以通過(guò)執(zhí)行函數(shù)來(lái)改變父作用域中某些屬性的值,來(lái)達(dá)到一些預(yù)期的效果。示例代碼如下:
示例八:引用綁定示例
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script> angular.module('isolateScope', []) .directive("isolateDirective", function () { return { replace : true, scope : { isolates : '&', }, link : function($scope, $element, $attr) { var func = $scope.isolates(); func(); } }; }) .controller("ctrl", function ($scope) { $scope.func = function () { console.log("Nick DeveloperWorks"); } }); </script> <body ng-app="isolateScope" > <div ng-controller="ctrl"> <div isolate-directive data-isolates="func"></div> </div> </body> </html>
這個(gè)例子中,瀏覽器的控制臺(tái)將會(huì)打印“Nick DeveloperWorks”文字。
上面的代碼中我們?cè)诟缸饔糜蛑兄付艘粋€(gè)函數(shù)對(duì)象$scope.func
,在孤立作用域中通過(guò)對(duì) HTML 屬性的綁定從而引用了 func。需要注意的是 link 函數(shù)中對(duì) func 對(duì)象的使用方法,$scope.isolates
獲得的僅僅是函數(shù)對(duì)象,而不是調(diào)用這個(gè)對(duì)象,因此我們需要在調(diào)用完$scope.isolates
之后再調(diào)用這個(gè)函數(shù),才能得到真正的執(zhí)行結(jié)果。
雙向綁定(=或者=attr)
雙向綁定賦予 AngularJS 孤立作用域與外界最為自由的雙向數(shù)據(jù)通信功能。在雙向綁定模式下,孤立作用域能夠直接讀寫父作用域中的屬性和數(shù)據(jù)。和以上兩種孤立作用域定義數(shù)據(jù)綁定一樣,雙向綁定也必須在父作用域的 HTML 中設(shè)定屬性節(jié)點(diǎn)來(lái)綁定。
雙向綁定非常適用于一些子 directive 需要頻繁和父作用域進(jìn)行數(shù)據(jù)交互,并且數(shù)據(jù)比較復(fù)雜的場(chǎng)景。不過(guò),由于可以自由的讀寫父作用域中的屬性和對(duì)象,所以在一些多個(gè) directive 共享父作用域數(shù)據(jù)的場(chǎng)景下需要小心使用,很容易引起數(shù)據(jù)上的混亂。
示例代碼如下:
示例九:雙向綁定示例
<!doctype html> <html> <head> <meta charset=utf-8"/> <title>scope nick</title> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <script> angular.module('isolateScope', []) .directive("isolateDirective", function () { return { replace : true, template: '<button>{{isolates}}</button>', scope : { isolates : '=', }, link : function($scope, $element, $attr) { $scope.isolates.name = "NICK"; } }; }) .controller("ctrl", function ($scope) { $scope.btns = { name : 'nick', dw : 'DeveloperWorks' }; }); </script> <body ng-app="isolateScope" > <div ng-controller="ctrl"> <button>{{btns.dw}}</button> <button>{{btns.name}}</button> <div isolate-directive data-isolates="btns"></div> </div> </body> </html>
上面的代碼運(yùn)行的結(jié)果是瀏覽器頁(yè)面上出現(xiàn)三個(gè)按鈕,其中第一個(gè)按鈕標(biāo)題為“DeveloperWorks”,第二和第三個(gè)按鈕的標(biāo)題為“NICK”。
初始時(shí)父作用域中的$scope.btns.name
為小寫的“nick”,通過(guò)雙向綁定,孤立作用域中將父作用域的 name改寫成為大寫的“NICK”并且直接生效,父作用域的值被更改。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
詳解Angular數(shù)據(jù)綁定及其實(shí)現(xiàn)方式
數(shù)據(jù)綁定是將應(yīng)用程序UI或用戶界面綁定到模型的機(jī)制。使用數(shù)據(jù)綁定,用戶將能夠使用瀏覽器來(lái)操縱網(wǎng)站上存在的元素。2021-05-05angular中實(shí)現(xiàn)li或者某個(gè)元素點(diǎn)擊變色的兩種方法
本篇文章主要介紹了angular中實(shí)現(xiàn)li或者某個(gè)元素點(diǎn)擊變色的兩種方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-07-07詳解封裝基礎(chǔ)的angular4的request請(qǐng)求方法
這篇文章主要介紹了詳解封裝基礎(chǔ)的angular4的request請(qǐng)求方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06AngularJS解決ng-if中的ng-model值無(wú)效的問(wèn)題
本篇文章主要介紹了AngularJS解決ng-if中的ng-model值無(wú)效的問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Angular?項(xiàng)目實(shí)現(xiàn)國(guó)際化的方法
本篇文章主要介紹了Angular?項(xiàng)目實(shí)現(xiàn)國(guó)際化的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧<BR>2018-01-01