摘要:比如,我們可以監(jiān)聽(tīng)事件由實(shí)例發(fā)出,然后在任何瀏覽器中就是變化的時(shí)候都會(huì)得到通知,如下所示每一個(gè)作用域?qū)ο蠖紩?huì)有這個(gè)方法,可以用來(lái)注冊(cè)一個(gè)作用域事件的偵聽(tīng)器。這個(gè)函數(shù)所扮演的偵聽(tīng)器在被調(diào)用時(shí)會(huì)有一個(gè)對(duì)象作為第一個(gè)參數(shù)。
上一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(二)
下一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(四)
書(shū)名:Mastering Web Application Development with AngularJS
深入探討 Scope 作用域Chapter 1
每一個(gè) $scope 都是類(lèi) Scope 的一個(gè)實(shí)例。類(lèi) Scope 擁有可以控制 scope 生命周期的方法,提供事件傳播的能力,并支持模板渲染。
讓我們?cè)賮?lái)看看這個(gè)簡(jiǎn)單的 HelloCtrl 的例子:
var HelloCtrl = function($scope){ $scope.name = "World"; }
HelloCtrl 看起來(lái)就跟普通的 JavaScript 構(gòu)造函數(shù)沒(méi)什么區(qū)別,事實(shí)上,除了 $scope 這個(gè)參數(shù)之外,確實(shí)沒(méi)什么新奇之處。不過(guò),這個(gè)參數(shù)究竟是從哪里來(lái)的呢?
這個(gè)新的作用域是由 ng-controller指令使用 Scope.$new() 方法生成的。等一下,這么說(shuō)來(lái)我們必須至少擁有一個(gè) scope 的實(shí)例才能創(chuàng)建新的 scope!沒(méi)錯(cuò),AngularJS其實(shí)有一個(gè) $rootScope(這個(gè)是所有其他作用域的父級(jí))。這個(gè) $rootScope 實(shí)例是在一個(gè)新的應(yīng)用啟動(dòng)的時(shí)候創(chuàng)建的。
ng-controller指令就是 可以創(chuàng)建作用域 指令的其中一個(gè)。AngularJS 會(huì)在任何它在DOM樹(shù)中碰到這種 可以創(chuàng)建作用域 指令的時(shí)候創(chuàng)建一個(gè)新的 Scope類(lèi)的實(shí)例。這些新創(chuàng)建的作用域通過(guò) $parent 屬性指向它自身的父作用域。DOM樹(shù)中會(huì)有很多 可以創(chuàng)建作用域 的指令,結(jié)果就是,很多作用域被創(chuàng)建了。
作用域的形式類(lèi)似于父子、樹(shù)狀的關(guān)系,并且最根部的就是 $rootScope 實(shí)例。就像作用域是被DOM樹(shù)驅(qū)動(dòng)著創(chuàng)建的一樣,作用域樹(shù)也是在模仿 DOM 的結(jié)構(gòu)。
現(xiàn)在你已經(jīng)知道了,一些指令會(huì)創(chuàng)建新的子級(jí)的作用域,你可能會(huì)想,為什么會(huì)需要這些復(fù)雜的東西。要想理解這一點(diǎn),我們來(lái)演示一個(gè)例子,其中使用了 ng-repeat 循環(huán)指令。
控制器如下:
var WorldCtrl = function ($scope) { $scope.population = 7000; $scope.countries = [ {name: "France", population: 63.1}, {name: "United Kingdom", population: 61.8}, ]; };
模版如下:
這個(gè) ng-repeat 指令可以迭代一個(gè) countries 的集合,并且為集合中的每一項(xiàng)都創(chuàng)建新的DOM 元素。ng-repeat 指令的語(yǔ)法非常容易理解;其中每一項(xiàng)都需要一個(gè)新的變量 country,并把它掛到 $scope 上面,以便視圖渲染使用。
但這里有一個(gè)問(wèn)題,就是,每一個(gè) country 都需要將一個(gè)新的變量掛載到一個(gè) $scope 上去,而我們也不能就簡(jiǎn)單的覆蓋掉前面被掛在上去的值。AngularJS 通過(guò)為集合中的每一個(gè)元素都創(chuàng)建一個(gè)新的作用域來(lái)解決這個(gè)問(wèn)題。新創(chuàng)建的這些作用域跟相匹配的DOM樹(shù)結(jié)構(gòu)非常相像,我們也能通過(guò)之前提到的那個(gè)牛逼的 Chrome 擴(kuò)展 Batarang 來(lái)可視化的看到這一點(diǎn),下面是屏幕截圖:
正如我們?cè)诮貓D中所看到的,每一個(gè)作用域(以矩形標(biāo)注邊界)維護(hù)屬于她自己的一段數(shù)據(jù)模型。給不同的作用域增加同名的變量是完全沒(méi)有問(wèn)題的,不會(huì)發(fā)生命名沖突(不同的DOM元素會(huì)指向不同的作用域,并使用相對(duì)應(yīng)的作用域的變量來(lái)渲染模板)。這樣一來(lái),每個(gè)元素又有自己的命名空間,在前面的例子中,每一個(gè) 元素都有自己的作用域,而 country 變量就定義在各自的作用域上面。
定義在作用于上的屬性對(duì)他的子級(jí)作用于來(lái)說(shuō)是可見(jiàn)的,試想一下,子級(jí)作用域并不需要重復(fù)定義同名的屬性!這在實(shí)踐中是非常有用的,因?yàn)槲覀儾槐匾槐橛忠槐榈闹貜?fù)定義本來(lái)可以通過(guò)作用域鏈得到的那些屬性。
再來(lái)看看前面的例子,假設(shè)我們想要顯示給出的這些國(guó)家與世界總?cè)丝诘陌俜直?。要?shí)現(xiàn)這個(gè)功能,我們可以在一個(gè)作用域上定義一個(gè) worldsPercentage 的方法,并由 WorldCtrl 來(lái)管理,如下所以:
$scope.worldsPercentage = function (countryPopulation) { return (countryPopulation / $scope.population)*100; }
然后被 ng-repeat 創(chuàng)建的每一個(gè)作用域?qū)嵗紒?lái)調(diào)用這個(gè)方法,如下:
AngularJS中作用域的繼承規(guī)則跟 JavaScript 中原型的繼承規(guī)則是相同的(在需要讀取一個(gè)屬性的時(shí)候,會(huì)一直向繼承樹(shù)的上方查詢(xún),直到找到了這個(gè)屬性為止)。
這種透過(guò)作用域?qū)哟侮P(guān)系的繼承,在讀數(shù)據(jù)的時(shí)候顯得非常的直觀、易于理解。但是在寫(xiě)數(shù)據(jù)的時(shí)候,就變的有點(diǎn)復(fù)雜了。
讓我們來(lái)看看,如果我們?cè)谝粋€(gè)作用域上定義了一個(gè)變量,先不管是否在子級(jí)作用域上。JavaScript代碼如下:
var HelloCtrl = function ($scope) { };
視圖的代碼如下:
Hello, {{name}}
Say hello to:Hello, {{name}}!
運(yùn)行一下這段代碼,就可以發(fā)現(xiàn),這個(gè) name 變量盡管僅僅是定義在了最頂級(jí)的作用域上,但在整個(gè)應(yīng)用中都是可見(jiàn)的!這說(shuō)明變量是從作用域鏈上繼承下來(lái)的。換句話說(shuō),變量是在父級(jí)作用域上定義的,然后在子級(jí)作用域中訪問(wèn)的。
現(xiàn)在,我們一起來(lái)看看,如果在 中寫(xiě)點(diǎn)字會(huì)發(fā)生什么,結(jié)果如下圖所示:
你可能會(huì)感到吃驚,因?yàn)?HelloCtrl 控制器所初始化的作用域創(chuàng)建了一個(gè)新的變量,而不是直接去修改 $rootScope 實(shí)例中的值。不過(guò)當(dāng)我們認(rèn)識(shí)到作用域也只不過(guò)是在彼此間進(jìn)行了原型繼承,也就不會(huì)覺(jué)得那么吃驚了。所有可以用在 JavaScript 對(duì)象上的原型繼承的規(guī)則,都可以同等的用在 作用域 的原型鏈繼承上去。畢竟 Scopes 作用域就是 JavaScript 對(duì)象嘛。
在子級(jí)作用域中去改變父級(jí)作用域上面的屬性有幾種方法。第一種,我們就直接通過(guò) $parent 屬性來(lái)引用父級(jí)作用域,但我們要看到,這是一個(gè)非常不可靠的解決方案。麻煩之處就在于,ng-model 指令所使用的表達(dá)式非常嚴(yán)重的依賴(lài)于整個(gè)DOM結(jié)構(gòu)。比如就在 標(biāo)簽上面的哪里插入另一個(gè) 可創(chuàng)建作用域 的指令,那 $parent 就會(huì)指向一個(gè)完全不同的作用域了。
就經(jīng)驗(yàn)來(lái)講,盡量避免使用 $parent 屬性,因?yàn)樗鼜?qiáng)制的把 AngularJS 表達(dá)式和你的模板所創(chuàng)建的 DOM 結(jié)構(gòu)捆綁在了一起。這樣一來(lái),HTML結(jié)構(gòu)的一個(gè)小小的改動(dòng),都可能會(huì)讓整個(gè)應(yīng)用崩潰。
另一個(gè)解決方案就是,不要直接把屬性綁定到 作用域上,而是綁到一個(gè)對(duì)象上面,如下所示:
Hello, {{thing.name}}
Say hello to:Hello, {{thing.name}}!
這個(gè)方案會(huì)更可靠,因?yàn)樗](méi)有假設(shè) DOM 樹(shù)的結(jié)構(gòu)是什么樣子。
避免直接把數(shù)據(jù)綁定到 作用域的屬性上。應(yīng)優(yōu)先選擇把數(shù)據(jù)雙向綁定到對(duì)象的屬性上(然后再把對(duì)象掛到 scope 上)。
就經(jīng)驗(yàn)而言,在給 ng-model 指令的表達(dá)式中,你應(yīng)該有一個(gè)點(diǎn)(例如, ng-model="thing.name")。
層級(jí)關(guān)系中的作用域可以使用 event bus(一種事件系統(tǒng))。AngularJS可以在作用域?qū)蛹?jí)中傳播具名的裝備齊全的事件。事件可以從任何一個(gè)作用域中發(fā)出,然后向上($emit)和向下($broadcast)四處傳播。
AngularJS核心服務(wù)和指令使用這種事件巴士來(lái)發(fā)出一些應(yīng)用程序狀態(tài)變化的重要事件。比如,我們可以監(jiān)聽(tīng) $locationChangeSuccess 事件(由 $rootScope 實(shí)例發(fā)出),然后在任何 location(瀏覽器中就是URL)變化的時(shí)候都會(huì)得到通知,如下所示:
$scope.$on("$locationChangeSuccess", function(event, newUrl, oldUrl){ //react on the location change here //for example, update breadcrumbs based on the newUrl });
每一個(gè)作用域?qū)ο蠖紩?huì)有這個(gè) $on 方法,可以用來(lái)注冊(cè)一個(gè)作用域事件的偵聽(tīng)器。這個(gè)函數(shù)所扮演的偵聽(tīng)器在被調(diào)用時(shí)會(huì)有一個(gè) event 對(duì)象作為第一個(gè)參數(shù)。后面的參數(shù)會(huì)根據(jù)事件類(lèi)型的不同與事件本身的配備一一對(duì)應(yīng)。
類(lèi)似于 DOM 事件,我們可以調(diào)用 event 對(duì)象的 preventDefault() 和 stopPropagation() 方法。stopPropagation() 方法將會(huì)阻止事件沿著作用域?qū)蛹?jí)繼續(xù)冒泡,并且只在事件向上層傳播的時(shí)候($emit)才有效。
盡管 AngularJS 的事件系統(tǒng)是模仿了 DOM 的,但兩個(gè)事件傳播系統(tǒng)是完全獨(dú)立的,沒(méi)有任何共同之處。
雖然在作用域?qū)蛹?jí)中傳播事件對(duì)一些問(wèn)題來(lái)說(shuō)是一種非常優(yōu)雅方案(特別是對(duì)全局的,異步的狀態(tài)變化來(lái)說(shuō)),但還是要適度使用。通常情況下,可以依靠雙向數(shù)據(jù)綁定來(lái)得到一個(gè)比較干凈的方案。在整個(gè) AngularJS 框架中,一共只發(fā)出($emit)了三個(gè)事件($includeContentRequested,$includeContentLoaded,$viewContentLoaded)和七個(gè)廣播($broadcast)($locationChangeStart, $locationChangeSuccess, $routeUpdate, $routeChangeStart, $routeChangeSuccess, $routeChangeError, $destroy)。正如你所看到的,作用域事件使用的非常少,我們應(yīng)該在發(fā)送自定義的事件之前認(rèn)真的評(píng)估一下其他的可選方案(多數(shù)會(huì)是雙向數(shù)據(jù)綁定)。
千萬(wàn)不要在 AngularJS 中模仿 DOM 的基于事件的編程方式。大多數(shù)情況下,你的應(yīng)用會(huì)有更好的架構(gòu)方式,你也可以在雙向數(shù)據(jù)綁定這條路上深入探索。
作用域需要提供相互隔離的命名空間,避免變量的命名沖突。作用域們都很小,而且被以層級(jí)的方式組織起來(lái),對(duì)內(nèi)存使用的管理來(lái)說(shuō)很有幫助。當(dāng)其中一個(gè)作用域不再需要 ,它就可以被銷(xiāo)毀了。結(jié)果就是,這個(gè)作用域所暴露出來(lái)的模型和方法就符合的垃圾回收的標(biāo)準(zhǔn)。
新的作用域通常是被 可創(chuàng)建作用域 的指令所生成和銷(xiāo)毀的。不過(guò)也可以使用 $new() 和 $destroy() 方法來(lái)手動(dòng)的創(chuàng)建和銷(xiāo)毀作用域。
轉(zhuǎn)載請(qǐng)注明來(lái)自[超2真人]
本文鏈接:http://www.peichao01.com/static_content/doc/html/Mastering_Web_Application_Development_with_AngularJS_3.html
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77976.html
摘要:本書(shū)的這一部分將為隨后的章節(jié)打下基礎(chǔ),會(huì)涵蓋模板,模塊化,和依賴(lài)注入。本書(shū)的小例子中我們會(huì)使用未經(jīng)壓縮的,開(kāi)發(fā)友好的版本,在的上。作用域也可以針對(duì)特定的視圖來(lái)擴(kuò)展數(shù)據(jù)和特定的功能。 上一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(一) 下一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(三) 原版書(shū)名:Mastering Web Application D...
摘要:模塊和依賴(lài)注入細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn)了,到目前為止所用到的例子都是使用的全局的構(gòu)造函數(shù)來(lái)定義控制器的。這非常的簡(jiǎn)單,只需使用如下參數(shù)來(lái)調(diào)用即可控制器的名字字符串類(lèi)型控制器的構(gòu)造函數(shù)全局定義的控制器構(gòu)造函數(shù)只適用于快速示例和原型開(kāi)發(fā)。 上一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(三) 下一篇: 書(shū)名:Mastering Web Application Develop...
摘要:上一篇譯精通使用開(kāi)發(fā)四下一篇譯精通使用開(kāi)發(fā)六書(shū)名合作對(duì)象正如所見(jiàn),提供了一種將對(duì)象組織為模塊的方式。模塊不僅可以注冊(cè)可以直接被框架所調(diào)用的對(duì)象控制器,過(guò)濾器等,還可以使用任何應(yīng)用開(kāi)發(fā)者所定義的對(duì)象。 上一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(四) 下一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(六) 書(shū)名:Mastering Web Applic...
摘要:下一篇譯精通使用開(kāi)發(fā)二原版書(shū)名第一章之道這一章主要是介紹,包括這個(gè)框架以及它背后的項(xiàng)目。幸運(yùn)的是,擁有一個(gè)活躍的,支持度高的社區(qū)。另外,社區(qū)還為已經(jīng)存在的工具箱里貢獻(xiàn)了許多有意思的工具。 下一篇:【譯】《精通使用AngularJS開(kāi)發(fā)Web App》(二) 原版書(shū)名:Mastering Web Application Development with AngularJS Ch...
閱讀 3990·2021-11-22 13:53
閱讀 1732·2021-08-25 09:39
閱讀 2442·2019-08-29 18:36
閱讀 1512·2019-08-26 13:35
閱讀 1246·2019-08-26 11:57
閱讀 1711·2019-08-23 15:57
閱讀 831·2019-08-23 14:55
閱讀 1190·2019-08-23 14:51