亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入探究AngularJS框架中Scope對象的超級教程

2019-11-20 10:52:00
字體:
來源:轉載
供稿:網友

一、遇到的問題
問題發生在使用 AngularJS 嵌套 Controller 的時候。因為每個 Controller 都有它對應的 Scope(相當于作用域、控制范圍),所以 Controller 的嵌套,也就意味著 Scope 的嵌套。這個時候如果兩個 Scope 內都有同名的 Model 會發生什么呢?從子 Scope 怎樣更新父 Scope 里的 Model 呢?

這個問題很典型,比方說當前頁面是一個產品列表,那么就需要定義一個 ProductListController

function ProductListController($scope, $http) {  $http.get('/api/products.json')    .success(function(data){      $scope.productList = data;    });  $scope.selectedProduct = {};}

你大概看到了在 Scope 里還定義了一個 selectedProduct 的 Model,表示選中了某一個產品。這時會獲取該產品詳情,而頁面通過 AngularJS 中的 $routeProvider 自動更新,拉取新的詳情頁模板,模板中有一個 ProductDetailController

function ProductDetailController($scope, $http, $routeParams) {  $http.get('/api/products/'+$routeParams.productId+'.json')    .success(function(data){      $scope.selectedProduct = data;    });}

有趣的事情發生了,在這里也有一個 selectedProduct ,它會怎樣影響 ProductListController 中的 selectedProduct 呢?

答案是沒有影響。在 AnuglarJS 里子 Scope 確實會繼承父 Scope 中的對象,但當你試下對基本數據類型(string, number, boolean)的 雙向數據綁定 時,就會發現一些奇怪的行為,繼承并不像你想象的那樣工作。子 Scope 的屬性隱藏(覆蓋)了父 Scope 中的同名屬性,對子 Scope 屬性(表單元素)的更改并不更新父 Scope 屬性的值。這個行為實際上不是 AngularJS 特有的,JavaScript 本身的原型鏈就是這樣工作的。開發者通常都沒有意識到 ng-repeat, ng-switch, ng-view 和 ng-include 統統都創建了他們新的子 scopes,所以在用到這些 directive 時也經常出問題。

二、解決的辦法
解決的辦法就是不使用基本數據類型,而在 Model 里永遠多加一個點.

使用

<input type="text" ng-model="someObj.prop1">

來替代

<input type="text" ng-model="prop1">

是不是很坑爹?下面這個例子很明確地表達了我所想表達的奇葩現象

app.controller('ParentController',function($scope){  $scope.parentPrimitive = "some primitive"  $scope.parentObj = {};  $scope.parentObj.parentProperty = "some value";});app.controller('ChildController',function($scope){  $scope.parentPrimitive = "this will NOT modify the parent"  $scope.parentObj.parentProperty = "this WILL modify the parent";});

查看 在線演示 DEMO
但是我真的確實十分很非常需要使用 string number 等原始數據類型怎么辦呢?2 個方法――

在子 Scope 中使用 $parent.parentPrimitive。 這將阻止子 Scope 創建它自己的屬性。
在父 Scope 中定義一個函數,讓子 Scope 調用,傳遞原始數據類型的參數給父親,從而更新父 Scope 中的屬性。(并不總是可行)
三、JavaScript 的原型鏈繼承
吐槽完畢,我們來深入了解一下 JavaScript 的原型鏈。這很重要,特別是當你從服務器端開發轉到前端,你應該會很熟悉經典的 Class 類繼承,我們來回顧一下。

假設父類 parentScope 有如下成員屬性 aString, aNumber, anArray, anObject, 以及 aFunction。子類 childScope 原型繼承父類 parentScope,于是我們有:

201614150604637.png (619×257)

如果子 Scope 嘗試去訪問 parentScope 中定義的屬性,JavaScript 會先在子 Scope 中查找,如果沒有該屬性,則找它繼承的 scope 去獲取屬性,如果繼承的原型對象 parentScope 中都沒有該屬性,那么繼續在它的原型中尋找,從原型鏈一直往上直到到達 rootScope。所以,下面的表達式結果都是 ture:

childScope.aString === 'parent string'childScope.anArray[1] === 20childScope.anObject.property1 === 'parent prop1'childScope.aFunction() === 'parent output'

假設我們執行下面的語句

childScope.aString = 'child string'

原型鏈并沒有被查詢,反而是在 childScope 中增加了一個新屬性 aString。這個新屬性隱藏(覆蓋)了 parentScope 中的同名屬性。在下面我們討論 ng-repeat 和 ng-include 時這個概念很重要。

201614150634794.png (619×257)

假設我們執行這個操作:

childScope.anArray[1] = '22'childScope.anObject.property1 = 'child prop1'

原型鏈被查詢了,因為對象 anArray 和 anObject 在 childScope 中沒有找到。它們在 parentScope 中被找到了,并且值被更新。childScope 中沒有增加新的屬性,也沒有任何新的對象被創建。(注:在 JavaScript 中,array 和 function 都是對象)

201614150658628.png (608×257)

假設我們執行這個操作:

childScope.anArray = [100, 555]childScope.anObject = { name: 'Mark', country: 'USA' }

原型鏈沒有被查詢,并且子 Scope 新加入了兩個新的對象屬性,它們隱藏(覆蓋)了 parentScope 中的同名對象屬性。

201614150718718.png (608×320)

應該可以總結

如果讀取 childScope.propertyX,并且 childScope 有屬性 propertyX,那么原型鏈沒有被查詢。
如果設置 childScope.propertyX,原型鏈不會被查詢。
最后一種情況,

delete childScope.anArraychildScope.anArray[1] === 22 // true

我們從 childScope 刪除了屬性,則當我們再次訪問該屬性時,原型鏈會被查詢。刪除對象的屬性會讓來自原型鏈中的屬性浮現出來。

201614150741147.png (608×320)

四、AngularJS 的 Scope 繼承
創建新的 Scope,并且原型繼承:ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive with scope: true, directive with transclude: true
創建新的 Scope,但不繼承:directive with scope: { ... }。它會創建一個獨立 Scope。
注:默認情況下 directive 不創建新 Scope,即默認參數是 scope: false。

ng-include

假設在我們的 controller 中,

$scope.myPrimitive = 50;$scope.myObject  = {aNumber: 11};

HTML 為:

<script type="text/ng-template" id="/tpl1.html">  <input ng-model="myPrimitive"></script><div ng-include src="'/tpl1.html'"></div> <script type="text/ng-template" id="/tpl2.html">  <input ng-model="myObject.aNumber"></script><div ng-include src="'/tpl2.html'"></div>

每一個 ng-include 會生成一個子 Scope,每個子 Scope 都繼承父 Scope。

201614151048789.png (541×115)

輸入(比如”77″)到第一個 input 文本框,則子 Scope 將獲得一個新的 myPrimitive 屬性,覆蓋掉父 Scope 的同名屬性。這可能和你預想的不一樣。

201614151107899.png (541×124)

輸入(比如”99″)到第二個 input 文本框,并不會在子 Scope 創建新的屬性,因為 tpl2.html 將 model 綁定到了一個對象屬性(an object property),原型繼承在這時發揮了作用,ngModel 尋找對象 myObject 并且在它的父 Scope 中找到了。

201614151132150.png (541×124)

如果我們不想把 model 從 number 基礎類型改為對象,我們可以用 $parent 改寫第一個模板:

<input ng-model="$parent.myPrimitive">

輸入(比如”22″)到這個文本框也不會創建新屬性了。model 被綁定到了父 scope 的屬性上(因為 $parent 是子 Scope 指向它的父 Scope 的一個屬性)。

201614151212469.png (541×117)

對于所有的 scope (原型繼承的或者非繼承的),Angular 總是會通過 Scope 的 $parent, $$childHead 和 $$childTail 屬性記錄父-子關系(也就是繼承關系),圖中為簡化而未畫出這些屬性。

在沒有表單元素的情況下,另一種方法是在父 Scope 中定義一個函數來修改基本數據類型。因為有原型繼承,子 Scope 確保能夠調用這個函數。例如,

// 父 Scope 中$scope.setMyPrimitive = function(value) {  $scope.myPrimitive = value;

查看 DEMO

ng-switch
ng-switch 的原型繼承和 ng-include 一樣。所以如果你需要對基本類型數據進行雙向綁定,使用 $parent,或者將其改為 object 對象并綁定到對象的屬性,防止子 Scope 覆蓋父 Scope 的屬性。
ng-repeat
ng-repeat 有一點不一樣。假設在我們的 controller 里:

$scope.myArrayOfPrimitives = [ 11, 22 ];$scope.myArrayOfObjects  = [{num: 101}, {num: 202}]

還有 HTML:

<ul>  <li ng-repeat="num in myArrayOfPrimitives">    <input ng-model="num">  </li><ul><ul>  <li ng-repeat="obj in myArrayOfObjects">    <input ng-model="obj.num">  </li><ul>

對于每一個 Item,ng-repeat 創建新的 Scope,每一個 Scope 都繼承父 Scope,但同時 item 的值也被賦給了新 Scope 的新屬性(新屬性的名字為循環的變量名)。Angular ng-repeat 的源碼實際上是這樣的:

childScope = scope.$new(); // 子 scope 原型繼承父 scope ...   childScope[valueIdent] = value; // 創建新的 childScope 屬性

如果 item 是一個基礎數據類型(就像 myArrayOfPrimitives),本質上它的值被復制了一份賦給了新的子 scope 屬性。改變這個子 scope 屬性值(比如用 ng-model,即 num)不會改變父 scope 引用的 array。所以上面第一個 ng-repeat 里每一個子 scope 獲得的 num 屬性獨立于 myArrayOfPrimitives 數組:

201614151333896.png (440×153)

這樣的 ng-repeat 和你預想中的不一樣。在 Angular 1.0.2 及更早的版本,向文本框中輸入會改變灰色格子的值,它們只在子 Scope 中可見。Angular 1.0.3+ 以后,輸入文本不會再有任何作用了。
我們希望的是輸入能改變 myArrayOfPrimitives 數組,而不是子 Scope 里的屬性。為此我們必須將 model 改為一個關于對象的數組(array of objects)。

所以如果 item 是一個對象,則對于原對象的一個引用(而非拷貝)被賦給了新的子 Scope 屬性。改變子 Scope 屬性的值(使用 ng-model,即 obj.num)也就改變了父 Scope 所引用的對象。所以上面第二個 ng-repeat 可表示為:

201614151355015.png (560×152)

這才是我們想要的。輸入到文本框即會改變灰色格子的值,該值在父 Scope 和子 Scope 均可見。
ng-controller
使用 ng-controller 進行嵌套,結果和 ng-include 和 ng-switch 一樣是正常的原型繼承。所以做法也一樣不再贅述。然而“兩個 controller 使用 $scope 繼承來共享信息被認為是不好的做法”
應該使用 service 在 controller 間共享數據。

如果你確實要通過繼承來共享數據,那么也沒什么特殊要做的,子 Scope 可以直接訪問所有父 Scope 的屬性。
directives
這個要分情況來討論。

默認 scope: false 亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

国产成人精品一区| 国产精品成人免费视频| 日韩在线观看免费全集电视剧网站| 亚洲欧美精品伊人久久| 亚洲最大成人免费视频| 亚洲免费视频在线观看| 亚洲美腿欧美激情另类| 亚洲aⅴ日韩av电影在线观看| 97在线视频精品| 538国产精品一区二区免费视频| 91av在线网站| 日韩电影在线观看永久视频免费网站| 国产精品入口尤物| 91精品国产自产在线| 国产原创欧美精品| 一区二区三区视频免费| 精品香蕉在线观看视频一| 亚洲人成在线免费观看| 久久婷婷国产麻豆91天堂| 精品国产一区二区三区久久| 国产精品吴梦梦| 亚洲一区二区自拍| 国产精品视频区1| 欧美激情国产高清| 欧美亚洲激情视频| 亚洲欧美日韩一区二区三区在线| 孩xxxx性bbbb欧美| 91网站在线看| 亚洲成人三级在线| 亚洲国产第一页| 91国产中文字幕| 日韩精品视频免费专区在线播放| 欧美久久精品午夜青青大伊人| 亚洲国产日韩欧美在线动漫| 欧美国产日韩xxxxx| 亚洲视频精品在线| 国产精品一区二区三区免费视频| 91久久国产精品91久久性色| 国产亚洲精品一区二555| 国内外成人免费激情在线视频| 日本一区二区在线免费播放| 成人激情电影一区二区| 日韩动漫免费观看电视剧高清| 日韩精品视频三区| 欧美在线亚洲一区| 国产欧美一区二区白浆黑人| 欧美成人精品在线视频| 国产精品一区=区| 亚洲欧洲一区二区三区在线观看| 久久久免费在线观看| 伊人伊成久久人综合网小说| 91高清免费视频| 久久久久成人网| 欧美精品福利在线| 久久久99久久精品女同性| 亚洲国产精品久久精品怡红院| 国产精品久久久久不卡| 日韩在线www| 国产精品扒开腿做爽爽爽的视频| 成人国内精品久久久久一区| 成人网页在线免费观看| 国产一区二中文字幕在线看| 国产精品久久久久久久一区探花| 欧美激情视频在线观看| 国产精品高清免费在线观看| 欧美成人精品在线观看| 国产精品美女呻吟| 这里精品视频免费| 91美女片黄在线观看游戏| 亚洲电影成人av99爱色| 欧美日韩国产在线播放| 日韩欧美在线视频观看| 久久中文字幕在线视频| 国产91色在线| 久久影院资源网| 欧美黑人性生活视频| 久久大大胆人体| 国产va免费精品高清在线观看| 亚洲风情亚aⅴ在线发布| 久久成人精品一区二区三区| 欧美日韩中文在线| 国产丝袜一区二区三区免费视频| 欧美日韩精品国产| 久久这里有精品| 国产精品免费电影| 欧美肥臀大乳一区二区免费视频| 欧美在线视频一区| 久久九九热免费视频| 日韩在线免费观看视频| 国产精品美女久久久久久免费| 国内精品久久久久久影视8| 国产精品极品尤物在线观看| 国产在线日韩在线| 日韩电影中文字幕一区| 黄色成人在线播放| 国产精品久久久久久久久借妻| 91精品久久久久久久久青青| 久久久国产精品亚洲一区| 久久露脸国产精品| 日韩欧亚中文在线| 国产精品久久久久久av福利软件| 亚洲国产欧美一区二区三区久久| 欧美在线一区二区视频| 欧美亚洲日本黄色| 精品久久久国产| 欧美专区中文字幕| 成人观看高清在线观看免费| 4438全国亚洲精品在线观看视频| 伊是香蕉大人久久| 色噜噜久久综合伊人一本| 日韩中文av在线| 成人黄色生活片| 欧美午夜宅男影院在线观看| 欧美成年人网站| 8090理伦午夜在线电影| 亚洲欧美日韩一区二区三区在线| 成人做爽爽免费视频| 最新中文字幕亚洲| 日韩中文在线中文网在线观看| 九九精品在线播放| 一区国产精品视频| 国产精品视频网| 日本在线观看天堂男亚洲| 在线观看日韩视频| 亚洲视频在线视频| 97视频在线观看免费| 久久久久久久成人| 久久久国产精品一区| 国产精品色午夜在线观看| 亚洲图片在线综合| 精品国产乱码久久久久久虫虫漫画| 91欧美激情另类亚洲| 日韩精品在线免费观看| 欧美激情久久久| 狠狠色狠色综合曰曰| 久久久中精品2020中文| 精品亚洲精品福利线在观看| 国产精品久久久久久久久久久久| 亚洲免费中文字幕| 在线观看日韩专区| 日韩欧美成人免费视频| 91久热免费在线视频| 国产精品嫩草影院一区二区| 国产成人精品综合| 欧美巨乳在线观看| 日韩黄在线观看| 亚洲男人天堂网站| 中国china体内裑精亚洲片| 国产精品高潮视频| 亚洲白拍色综合图区| 亚洲最大av网| 国产精品高潮呻吟视频| 精品视频在线播放色网色视频| 日韩精品极品在线观看| 国产欧美日韩中文字幕在线| 日韩中文字幕视频在线观看| 少妇精69xxtheporn| 亚洲第一视频在线观看| 91国产精品91| 久久久免费观看| 久久精品亚洲94久久精品| 亚洲开心激情网| 日本精品中文字幕| zzjj国产精品一区二区|