javascript
html中scope的作用,AngularJS 作用域(Scope)
AngularJS 作用域(Scope)
作用域(Scope)
是一個存儲應(yīng)用數(shù)據(jù)模型的對象
為 表達式 提供了一個執(zhí)行上下文
作用域的層級結(jié)構(gòu)對應(yīng)于 DOM 樹結(jié)構(gòu)
作用域可以監(jiān)聽 表達式 的變化并傳播事件
作用域有什么
作用域提供了 ($watch) 方法監(jiān)聽數(shù)據(jù)模型的變化
作用域提供了 ($apply) 方法把不是由Angular觸發(fā)的數(shù)據(jù)模型的改變引入Angular的控制范圍內(nèi)(如控制器,服務(wù),及Angular事件處理器等)
作用域提供了基于原型鏈繼承其父作用域?qū)傩缘臋C制,就算是嵌套于獨立的應(yīng)用組件中的作用域也可以訪問共享的數(shù)據(jù)模型(這個涉及到指令間嵌套時作用域的幾種模式)
作用域提供了 表達式 的執(zhí)行環(huán)境,比如像 {{username}} 這個表達式,必須得是在一個擁有屬性這個屬性的作用域中執(zhí)行才會有意義,也就是說,作用域中可能會像這樣 scope.username 或是 $scope.username,至于有沒有 $ 符號,看你是在哪里訪問作用域了
作用域作為數(shù)據(jù)模型使用
作用域是Web應(yīng)用的控制器和視圖之間的粘結(jié)劑。在Angular中,最直觀的表現(xiàn)是:在自定義指令中,處在模版的 鏈接(linking) 階段時, 指令(directive)會設(shè)置一個 $watch 函數(shù)監(jiān)聽著作用域中各表達式(注:這個過程是隱式的)。這個 $watch 允許指令在作用域中的屬性變化時收到通知,
進而讓指令能夠根據(jù)這個改變來對DOM進行重新渲染,以便更新已改變的屬性值(注:屬性值就是scope對象中的屬性,也就是數(shù)據(jù)模型)。
其實,不止上面所說的指令擁有指向作用域的引用,控制器中也有(注:可以理解為控制器與指令均能引用到與它們相對應(yīng)的DOM結(jié)構(gòu)所處的作用域)。
但是控制器與指令是相互分離的,而且它們與視圖之間也是分離的,這樣的分離,或者說耦合度低,可以大大提高對應(yīng)用進行測試的工作效率。
注:其實可以很簡單地理解為有以下兩個鏈條關(guān)系:
控制器 --> 作用域 --> 視圖(DOM)
指令 --> 作用域 --> 視圖(DOM)
讓我們來看下面一個例子,可以說明作用域作為視圖與控制器的黏合劑:
源碼
Your name:
greet
function MyController($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}
效果
Your name:
greet
在上面這個例子中,我們有:
控制器:MyController,它引用了 $scope 并在其上注冊了兩個屬性和一個方法
$scope 對象:持有上面例子所需的數(shù)據(jù)模型,包括 username 屬性、greeting屬性(注:這是在sayHello()方法被調(diào)用時注冊的)和 sayHello() 方法
視圖:擁有一個輸入框、一個按鈕以及一個利用雙向綁定來顯示數(shù)據(jù)的內(nèi)容塊
那么具體整個示例有這樣兩個流程,從控制器發(fā)起的角度來看就是:
控制器往作用域中寫屬性:給作用域中的 username 賦值,然后作用域通知視圖中的 input 數(shù)據(jù)變化了,input 因為通過 ng-model 實現(xiàn)了雙向綁定可以知道 username 的變化,進而在視圖中渲染出改變的值,這里是 World
控制器往作用域中寫方法給作用域中的 sayHello() 方法賦值,該方法被視圖中的 button 調(diào)用,因為 button 通過 ng-click 綁定了該方法,當(dāng)用戶點擊按鈕時,sayHello() 被調(diào)用,這個方法讀取作用域中的 username 屬性,加上前綴字符串 Hello,然后賦值給在作用域中新創(chuàng)建的 greeting 屬性
整個示例的過程如果從視圖的角度看,那主要是以下三個部分:
input 中的渲染邏輯:展示了通過 ng-model 進行的作用域和 視圖中某表單元素的雙向綁定
根據(jù) ng-model 中的 username 去作用域中取,如果已經(jīng)有值,那么用這個默認值填充當(dāng)前的輸入框
接受用戶輸入,并且將用戶輸入的字符串傳給 username,這時候作用域中的該屬性值實時更新為用戶輸入的值
button 中的邏輯
接受用戶單擊,調(diào)用作用域中的 sayHello() 方法
{{greeting}} 的渲染邏輯
在用戶未單擊按鈕時,不顯示內(nèi)容
取值階段:在用戶單擊后,這個表達式會去scope中取 greeting 屬性,而這個作用域和控制器是同一個的(這個例子中),這時候,該作用域下 greeting 屬性已經(jīng)有了,這時候這個屬性就被取回來了
計算階段:在當(dāng)前作用域下去計算 greeting 表達式 ,然后渲染視圖,顯示 HelloWorld
經(jīng)過以上的兩種角度分析示例過程,我們可以知道:作用域(scope)對象以及其屬性是視圖渲染的唯一數(shù)據(jù)來源。
從測試的角度來看,視圖與控制器分離的需求在于它允許測試人員可以單獨對應(yīng)用的操作邏輯進行測試,而不必考慮頁面的渲染細節(jié)。
it('should say hello', function() {
var scopeMock = {};
var cntl = new MyController(scopeMock);
// 確保username被預(yù)先填充為World
expect(scopeMock.username).toEqual('World');
// 確保我們輸入了新的username后得到了正確的greeting值
scopeMock.username = 'angular';
scopeMock.sayHello();
expect(scopeMock.greeting).toEqual('Hello angular!');
});
作用域分層結(jié)構(gòu)
如上所說,作用域的結(jié)構(gòu)對應(yīng)于DOM結(jié)構(gòu),那么最頂層,和DOM樹有根節(jié)點一樣,每個Angular應(yīng)用有且僅有一個 root scope,當(dāng)然啦,子級作用域就和DOM樹的子節(jié)點一樣,可以有多個的。
應(yīng)用可以擁有多個作用域,比如 指令 會創(chuàng)建子級作用域(至于指令創(chuàng)建的作用域是有多種類型的,詳情參加指令相關(guān)文檔)。一般情況下,當(dāng)新的作用域被創(chuàng)建時,它是以嵌入在父級作用域的子級的形式被創(chuàng)建的,這樣就形成了與其所關(guān)聯(lián)的DOM樹相對應(yīng)的一個作用域的樹結(jié)構(gòu)。(譯注:作用域的層級繼承是基于原型鏈的繼承,所以在下面的例子中會看到,讀屬性時會一直往上溯源,直到有未知)
作用域的分層的一個簡單例子是,假設(shè)現(xiàn)在HTML視圖中有一個表達式 {{name}} ,正如上面解釋過,Angular需要經(jīng)歷取值和計算兩個階段才能最終在視圖渲染結(jié)果。那么這個取值的階段,其實就是根據(jù)作用域的這個層級結(jié)構(gòu)(或樹狀結(jié)構(gòu))來進行的。
首先,Angular在該表達式當(dāng)前所在的DOM節(jié)點所對應(yīng)的作用域中去找有沒有 name 這個屬性
如果有,Angular返回取值,計算渲染;如果在當(dāng)前作用域中沒有找到,那么Angular繼續(xù)往上一層的父級作用域中去找 name 屬性,直到找到為止,最后實在沒有,那就到達 $rootScope 了
上面一個簡單的例子展示了在作用域分層結(jié)構(gòu)中找屬性,是基于原型繼承的模式。接下來這個demo用一個圖具體展示了作用域的層級結(jié)構(gòu),讓你可以有更直觀的了解。
源碼
Hello !
.show-scope-demo.ng-scope,
.show-scope-demo .ng-scope {
border: 1px solid red;
margin: 3px;
}
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
效果
看到上面的框中,注意,Angular會自動為每個擁有作用域的DOM節(jié)點加上 ng-scope 類。上圖中,擁有紅色邊框樣式的節(jié)點,就意味著該節(jié)點擁有了自己的作用域,無論它是通過什么方式創(chuàng)建的(譯注:上面可以看到有通過控制器創(chuàng)建的新的作用域,也有通過指令如 ng-repeat 創(chuàng)建的)。上例中,ng-repeat 創(chuàng)建的子級作用域是極其必要的,因為每個
中想要渲染輸出的 {{name}} 顯然是不同的值,那就需要為它們提供不同的作用域。同樣的,Angular在渲染 {{department}} 表達式時,先在當(dāng)前和 相對應(yīng)的作用域去找有沒有這個屬性,如果沒有,接著往上找,在這個例子中,直到找到 $rootScope 下時,才找到 department 屬性,然后將其取回,計算,渲染輸出。從DOM中抓取作用域
作用域?qū)ο笫桥c指令或控制器等Angular元素所在的DOM節(jié)點相關(guān)聯(lián)的,也就是說,其實DOM節(jié)點上是可以抓取到作用域這個對象的(當(dāng)然,為了調(diào)試偶爾會用,一般不用)。
而對于 $rootScope 在哪里抓呢?它藏在 ng-app 指令所在的那個DOM節(jié)點之中,請看更多關(guān)于 ng-app 指令。通常,ng-app 放在 標(biāo)簽中, 當(dāng)然,如果你的應(yīng)用中只是視圖的某一部分想要用Angular控制,那你可以把它放在想要控制的元素的最外層。
那來看看如何在調(diào)試的時候抓取作用域吧:
右鍵選去你想審查的元素,調(diào)出debugger,通常F12即可,這樣你選中的元素會高亮顯示(譯注:文檔都看到這的人了,會需要這句提示么?原文檔這是在賣萌么)
此時,調(diào)試器(debugger)允許你用變量 $0 來獲取當(dāng)前選取的元素
在console中執(zhí)行 angular.element($0).scope() 或直接輸入 $scope 即可看到你想要查詢的當(dāng)前DOM元素節(jié)點綁定的作用域了
基于作用域的事件傳播
作用域可以像DOM節(jié)點一樣,進行事件的傳播。主要是有兩個方法:
broadcasted :從父級作用域廣播至子級 scope
emitted :從子級作用域往上發(fā)射到父級作用域
讓我們來看個例子:
源碼
Root作用域MyEvent count:
$emit('MyEvent')
$broadcast('MyEvent')
Middle作用域MyEvent count:
Leaf作用域MyEvent count:
function EventController($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}
效果
譯注:上面例子很簡單,有幾個需要注意的是:
$emit 和 $broadcast 是直接被寫在 html 模版中的,而不是寫在控制器的 JavaScript代碼中,因為這兩個方法是直接在 $scope 中就有的,
同一個控制器 EventController 被用在了三個不同的DOM節(jié)點中(這是為了省事,通常不這樣寫的)
上面的事件無非就是點擊兩個按鈕,分別出發(fā)廣播/冒泡(發(fā)射)事件,然后在各節(jié)點設(shè)置監(jiān)聽,這里只要用 $scope.$on() 方法(注:如果在指令中,可能就是 scope.$on()),就可以進行監(jiān)聽了
作用域的生命周期
作用域的執(zhí)行上下文
譯注:這個小節(jié)應(yīng)該是在看完下個小節(jié)的基礎(chǔ)上再回過來看這個,所以建議先看下個小節(jié):scope生命周期拆解。由于要遵從原文檔的大體順序,所以順序沒做改動。
瀏覽器接收一個事件的標(biāo)準(zhǔn)的工作流程應(yīng)該是:
接收事件-->觸發(fā)回調(diào)-->回調(diào)執(zhí)行結(jié)束返回-->瀏覽器重繪DOM-->瀏覽器返回等待下一個事件
上面的過程中,如果一切都發(fā)生在Angular的執(zhí)行上下文的話,那相安無事,Angular能夠知道數(shù)據(jù)模型發(fā)生的改變;但是如果當(dāng)瀏覽器的控制權(quán)跑到原生的 JavaScript中去時(譯注:比如通過jQuery監(jiān)聽事件之類的非Angular的回調(diào)等),那么應(yīng)用執(zhí)行的上下文就發(fā)生在Angular的上下文之外了,這樣就導(dǎo)致Angular無法知曉數(shù)據(jù)模型的任何改變。想要讓Angular重新掌權(quán)并知曉正在發(fā)生的數(shù)據(jù)模型的變化的話,那就需要通過使用 $apply 方法讓上下文執(zhí)行環(huán)境重新進入到Angular的上下文中(注:用法 $scope.$apply())。只有執(zhí)行上下文重新回到Angular中,那樣數(shù)據(jù)模型的改變才能被Angular所識別并作出相應(yīng)操作(注:當(dāng)然,如果執(zhí)行上下文沒有發(fā)生改變,也就沒有必要顯式地去進行 $apply 操作)。舉個例子,像 ng-click 這個指令,監(jiān)聽DOM事件時,表達式的計算就必須放在 $apply() 中(注:例子不夠完備,待補充)。
在計算完表達式之后,$apply() 方法執(zhí)行Angular的 $digest 階段。
在 $digest 階段,scope 檢查所有通過 $watch() 監(jiān)測的表達式(或別的數(shù)據(jù))并將其與它們自己之前的值進行比較。這就是所謂的 臟值檢查(dirty checking)。
另外,需要注意的是,$watch() 的監(jiān)測是異步執(zhí)行的。這就意味著當(dāng)給一個作用域中的屬性被賦值時,如:$scope.username="angular",$watch() 方法不會馬上被調(diào)用,它會被延遲直到 digest() 階段跑完
(注:至于 $digest 階段到底是干嘛的,你可以認為就是個緩沖階段,而且是必要的階段)。
通過 $digest() 給我們提供的這個延遲是很有必要的,也正是應(yīng)用程序常常想要的(注:出于性能的考慮),因為有這個延遲,我們可以等待幾個或多個數(shù)據(jù)模型的改變/更新攢到一塊,
合并起來放到一個 $watch() 中去監(jiān)測,而且這樣也能從一定程度上保證在一個 $wathc() 在監(jiān)測期間沒有別的 $watch() 在執(zhí)行。
這樣,當(dāng)前的 $watch() 可以返回給應(yīng)用最準(zhǔn)確的更新通知,進而刷新試圖或是進入一個新的 $digest() 階段。
(譯注:這一段有點晦澀,可以看下面的一張圖結(jié)合著學(xué)習(xí);還有就是可以把整個過程想象為為了提升效率,
把多個同性質(zhì)的數(shù)據(jù)放在同一個 $digest 輪循中處理能夠大大提高效率,就像zf辦事經(jīng)常這樣,當(dāng)然,它們的效率不高,ng則不同,效率相對高)
scope生命周期拆解
相信看了上面一段話,沒理解的還是很多人,因為標(biāo)題雖說是講作用域的生命周期,但是一上來就跟我講的是關(guān)于Angular的執(zhí)行上下文,怎么也沒聯(lián)系到一塊。說實話,翻譯這段,真心有點要命的感覺。當(dāng)然,把它拆分成多個步驟來看,相信會更清晰,因為下面我們是真要講作用域的生命周期,讓我們來過一遍。
創(chuàng)建期
root scope 是在應(yīng)用程序啟動時由 $injector 創(chuàng)建的。另外,在指令的模版鏈接階段(template
linking),指令會創(chuàng)建一些新的子級 scope。
注冊$watch
在模版鏈接階段(template linking),指令會往作用域中注冊 監(jiān)聽器(watch),而且不止一個。這些 $watch 用來監(jiān)測數(shù)據(jù)模型的更新并將更新值傳給DOM。
數(shù)據(jù)模型變化
正如上面一節(jié)所提到的,要想讓數(shù)據(jù)模型的變化能夠很好的被Angular監(jiān)測,需要讓它們在 scope.$apply() 里發(fā)生。
當(dāng)然,對于Angular本身的API來講,無論是在控制器中做同步操作,還是通過 $http 或者 $timeout 做的非同步操作,
抑或是在Angular的服務(wù)中,是沒有必要手動去將數(shù)據(jù)模型變化的操作放到 $apply() 中去的,因為Angular已經(jīng)隱式的為我們做了這一點。
數(shù)據(jù)模型變化監(jiān)測
在把數(shù)據(jù)變化 $apply 進來之后,Angular開始進入 $digest 輪循(就是調(diào)用 $digest() 方法),首先是 rootscope 進入 $digest ,然后由其把各個監(jiān)聽表達式或是函數(shù)的任務(wù)傳播分配給所有的子級作用域,那樣各個作用域就各司其職了,如果監(jiān)聽到自己負責(zé)的數(shù)據(jù)模型有變化,馬上就調(diào)用 $watch 。(譯注:這里所說的從根scope往下分發(fā)是譯者自己的想法,如有錯誤,請糾正)
銷毀作用域
當(dāng)子級作用域不再需要的時候,這時候創(chuàng)建它們的就會負責(zé)把它們回收或是銷毀(注:比如在指令中,創(chuàng)建是隱式的,銷毀可以不但可以是隱式的,也可以是顯式的,如 scope.$destroy())。銷毀是通過 scope.$destroy() 這個方法。銷毀之后,$digest() 方法就不會繼續(xù)往子級作用域傳播了,這樣也就可以讓垃圾回收系統(tǒng)把這一個作用域上用來存放數(shù)據(jù)模型的內(nèi)存給回收利用了。
作用域和指令
在編譯(或說解析)階段, 編譯器在HTML解析器解析頁面遇到非傳統(tǒng)的或是自己不能識別的標(biāo)簽或別的表達式時,Angular編譯器就將這些HTML解析器不懂的東西(其實就是指令)在當(dāng)前的DOM環(huán)境下解析出來。通常,指令分為兩種,一種就是我們常說的指令,另外一種就是我們通常叫它Angular表達式的雙大括號形式,具體如下:
監(jiān)測型 指令 ,像雙大括號表達式 {{expression}} 。這種類型的指令需要在 $watch() 方法中注冊一個監(jiān)聽處理器(譯注:隱式還是顯式的需要看執(zhí)行上下文),來監(jiān)聽控制器或是別的操作引起的表達式值改變,進而來更新視圖。
監(jiān)聽型 指令 ,像 ng-click , 這種是在HTML標(biāo)簽屬性中直接寫好當(dāng) ng-click 發(fā)生時調(diào)用什么處理器,當(dāng)DOM監(jiān)聽到 ng-click 被觸發(fā)時,這個指令就會通過 $apply() 方法執(zhí)行相關(guān)的表達式操作或是別的操作進而更新視圖。
綜上,無論是哪種類型的指令,當(dāng)外部事件(可能是用戶輸入,定時器,ajax等)發(fā)生時,相關(guān)的 表達式 必須要通過 $apply() 作用于相應(yīng)的作用域,這樣所有的監(jiān)聽器才能被正確更新,然后進行后續(xù)的相關(guān)操作。
可以創(chuàng)建作用域的指令
大多數(shù)情況下, 指令和作用域相互作用,但并不創(chuàng)建作用域的新實例。但是,有一些特殊的指令,如 ng-controller 和 ng-repeat 等,則會創(chuàng)建新的下級作用域,并且把這個新創(chuàng)建的作用域和相應(yīng)的DOM元素相關(guān)聯(lián)。如前面說過的從DOM元素抓取作用域的方式(如果你還記得的話),就是調(diào)用 angular.element(aDomElement).scope() 方法。
作用域與控制器
作用域和控制器的交互大概有以下幾種情況:
控制器通過作用域?qū)δ0姹┞兑恍┓椒ü┢湔{(diào)用,詳情見 ng-controller
控制器中定義的一些方法(譯注:行為或操作邏輯)可以改變注冊在作用域下的數(shù)據(jù)模型(也就是作用域的屬性)
控制器在某些場合可能需要設(shè)置 監(jiān)聽器 來監(jiān)聽作用域中的數(shù)據(jù)模型(model)。這些監(jiān)聽器在控制器的相關(guān)方法被調(diào)用時立即執(zhí)行。
作用域$watch 性能
因為在Angular中對作用域進行臟值檢查($watch)實時跟蹤數(shù)據(jù)模型的變化是一個非常頻繁的操作,所以,進行臟值檢查的這個函數(shù)必須是高效的。一定要注意的是,用 $watch 進行臟值檢查時,一定不要做任何的DOM操作,因為DOM操作拖慢甚至是拖垮整體性能的能力比在 JavaScript對象上做屬性操作高好幾個數(shù)量級。
與瀏覽器事件輪循整合
下圖與示例描述了Angular如何與瀏覽器事件輪循進行交互。
瀏覽器的事件輪循等待事件到來,事件可以是用戶交互,定時器事件,或是網(wǎng)絡(luò)事件(如 ajax 返回)
事件發(fā)生,其回調(diào)被執(zhí)行,回調(diào)的執(zhí)行就使得應(yīng)用程序的執(zhí)行上下文進入到了 JavaScript 的上下文。然后在 JavaScript的上下文中執(zhí)行,并修改相關(guān)的DOM結(jié)構(gòu)
一旦回調(diào)執(zhí)行完畢,瀏覽器就離開 JavaScript的上下文回到瀏覽器上下文并基于DOM結(jié)構(gòu)的改變重新渲染視圖
講了那么多些,那么Angular是怎么在這里橫插一杠呢?看圖,Angular是插進了 JavaScript的上下文中,通過提供Angular自己的事件處理輪循來改變正常的JavaScript工作流。它其實是把JavaScript上下文很成了兩塊:一個是傳統(tǒng)的JavaScript執(zhí)行上下文(圖中淺藍色區(qū)域),一個是Angular的執(zhí)行上下文(圖中淡黃色區(qū)域)。
只有在Angular上下文執(zhí)行的操作才會受益于Angular的數(shù)據(jù)綁定,異常處理,屬性檢測,等等。當(dāng)然,如果不在Angular的上下文中,你也可以使用 $apply() 來進入Angular的執(zhí)行上下文。
需要注意的是,$apply() 在Angular本身的很多地方(如控制器,服務(wù)等)都已經(jīng)被隱式地調(diào)用了來處理事件輪循。
顯示地使用 $apply() 只有在你從 JavaScript上下文或是從第三方類庫的回調(diào)中想要進入Angular時才需要。讓我們來看看具體的流程:
進入Angular執(zhí)行上下文的方法,調(diào)用 scope.$apply(stimulusFn) 。上面 $apply() 中的參數(shù) stimulusFn 是你想要讓它進入Angular上下文的代碼
進入 $apply() 之后,Angular執(zhí)行 stimulusFn() ,而這個函數(shù)通常會改變應(yīng)用程序的狀態(tài)(可能是數(shù)據(jù),或是方法調(diào)用等)
之后,Angular進入 $digest 輪循。這個輪循是由兩個較小的輪循構(gòu)成,一個是處理 $evalAsync 隊列(異步計算的隊列),另一個是處理 $watch 列表。 $digest 輪循不斷迭代變更(在 $eval 和 $watch 之間變更)直到數(shù)據(jù)模型穩(wěn)定,這個狀態(tài)其實就是 evalAsync 隊列為空且$watch 列表不再監(jiān)測到變化為止。(譯注:其實這里就是所有外來的異步操作堆起來成為一個隊列,由$eval一個個計算,然后 $watch 看一下這個異步操作對應(yīng)的數(shù)據(jù)模型是否還有改變,有改變,就繼續(xù) $eval 這個異步操作,如果沒改變,那就拿異步操作隊列里的下個異步操作重復(fù)上述步驟,直到異步操作隊列為空以及 $watch 不再監(jiān)測到任何數(shù)據(jù)模型變化為止)
$evalAsync 隊列是用來安排那些待進入Angular$digest 的異步操作,這些操作往往是在瀏覽器的視圖渲染之前,且常常是通過 setTimeout(0) 觸發(fā)。但是用 setTimeout(0) 這個方法就不得不承受緩慢遲鈍的響應(yīng)以及可能引起的閃屏(因為瀏覽器在每次事件發(fā)生后都會渲染一次)(譯注:這里個人覺得不要理解的太復(fù)雜,按照上面第三點理解就夠用了,這邊個人翻譯的也不是太好,后期配以例子完善)
$watch 列表則是存放了一組經(jīng)過 $eval 迭代之后可能會改變的Angular的表達式集合。如果數(shù)據(jù)模型變化被監(jiān)測到,那么 $watch 函數(shù)被調(diào)用進而用新值更新DOM。
一旦Angular的 $digest 輪循完成,那么應(yīng)用程序的執(zhí)行就會離開Angular及 JavaScript的上下文。然后瀏覽器重新渲染DOM來反映發(fā)生的變化
接下來是傳統(tǒng)的 Helloworld 示例(就是本節(jié)的第一個例子)的流程剖析,這樣你應(yīng)該就能明白整個例子是如何在用戶輸入時產(chǎn)生雙向綁定的。
編譯階段:ng-model 和 input 指令 在 標(biāo)簽中設(shè)置了一個 keydown 監(jiān)聽器
在{{greeting}} 插值(也就是表達式)這里設(shè)置了一個 $watch 來監(jiān)測 username 的變化
執(zhí)行階段:在 輸入框中按下 'X' 鍵引起瀏覽器發(fā)出一個 keydown 事件
input 指令捕捉到輸入值的改變調(diào)用 $apply("username = 'X';") 進入Angular的執(zhí)行環(huán)境來更新應(yīng)用的數(shù)據(jù)模型
Angular將 username='X'; 作用在數(shù)據(jù)模型之上,這樣 scope.username 就被賦值為 'X' 了
$watch 列表中監(jiān)測到 username 有一個變化,然后通知 {{greeting}} 插值表達式,進而更新DOM
執(zhí)行離開Angular的上下文,進而 keydown 事件結(jié)束,然后執(zhí)行也就退出了 JavaScript的上下文;這樣 $digest 完成
瀏覽器用更新了的值重新渲染視圖
總結(jié)
以上是生活随笔為你收集整理的html中scope的作用,AngularJS 作用域(Scope)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机网络课程计划,计算机网络教学计划2
- 下一篇: 在计算机网络中可用于信息传输的介质,在计