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