首頁 web前端 js教程 詳解JavaScript的AngularJS框架中的作用域與資料綁定

詳解JavaScript的AngularJS框架中的作用域與資料綁定

Dec 24, 2016 am 10:27 AM

AngularJS 簡介
AngularJS 是由 Google 發起的一款開源的前端 MVC 腳本框架,既適合做普通 WEB 應用也可以做 SPA(單頁應用,所有的用戶操作都在一個頁面中完成)。與同為 MVC 框架的 Dojo 的定位不同,AngularJS 在功能上更加輕量級,而相比於 jQuery,AngularJS 又幫您省去了許多機械的綁定工作。在一些對開發速度要求高,功能模組不需要太豐富的非企業級 WEB 應用程式上,AngularJS 是一個非常好的選擇。 AngularJS 最為複雜同時也是最強大的部分就是它的資料綁定機制,這個機制幫助我們能更好的將注意力集中在資料的模型建立和傳遞上,而不是對底層的 DOM 進行低階的操作。

AngularJS 作用域
基於jQuery 的傳統WEB 應用中,為了監聽使用者的輸入等行為,需要為每一個DOM 元素設定一個監聽方法,也即是監聽DOM 上發生的各類事件,然後由jQuery 做出回應並展示在頁面上。這種方法簡單直觀,但是一旦WEB 應用變得龐大且複雜,那麼監聽程式碼就顯得非常的機械而且冗餘,更可怕的是,如果對於DOM 的事件監聽沒有做好管理,那麼很容易出現瀏覽器資源的洩漏。
針對以上所暴露的問題,AngularJS 用一系列指令來取代 jQuery 的事件綁定程式碼。為了能夠組織好各類指令之間的協調工作而不出現資料混亂,AngularJS 在模型層上引申出作用域的概念,以配合控制器來實現對視圖層的展現工作。
作用域(Scope)
AngularJS 中,作用域是指向應用模型的對象,它是表達式的執行環境。作用域有層次結構,這個層次和對應的 DOM 幾乎是一樣的。作用域能監控表達式和傳遞事件。
在HTML 程式碼中,一旦一個ng-app 指令被定義,那麼一個作用域就產生了,由ng-app 所產生的作用域比較特殊,它是一個根作用域($rootScope),它是其他所有$Scope 的最頂層。
清單 1. 生成根作用域

<html>
 <head><script src="angular.min.js"></script></head>
 <body data-ng-app="app">...</body>
</html>
登入後複製

   

除了用 ng-app 指令可以產生一個作用域之外,其他的指令如 ng-controller,ng-repeat 等都會產生一個或多個作用域。此外,還可以透過 AngularJS 提供的創建作用域的工廠方法來建立一個作用域。這些作用域都擁有自己的繼承上下文,且根作用域都是$rootScope。
在產生一個作用域之後,在編寫AngularJS 程式碼時,$scope 物件代表了這個作用域的資料實體,我們可以在$scope 內定義各種資料類型,之後可以直接在HTML 中以{{變數名}} 方式來讓HTML 存取到這個變量,程式碼如下:
清單2. 簡單的資料綁定

<script>
angular.module(&#39;app&#39;, [])
 .controller("ctrl", function ($scope) {
 $scope.btns = {
 ibm : &#39;ibm&#39;
 };
 });
</script>
</head>
<body data-ng-app="app" >
 <div data-ng-controller="ctrl">
 <button>{{btns.ibm}}</button>
 </div>
</body>
登入後複製

   

這就是AngularJS 中最簡單的資料綁定方式,同時也是應用最廣泛的資料綁定定方式。
繼承作用域(Inherited Scope)
AngularJS 在創建一個作用域時,會檢索上下文,如果上下文中已經存在一個作用域,那麼這個新創建的作用域就會以JavaScript 原型繼承機制繼承其父作用域的屬性和方法(有個例外是孤立作用域,下文討論)。
一些 AngularJS 指令會創建新的子作用域,並且進行原型繼承: ng-repeat、ng-include、ng-switch、ng-view、ng-controller, 用 scope: true 和 transclude: true 創建的 directive。
以下 HTML 中定義了三個作用域,分別是由 ng-app 指令所建立的$rootScope,parentCtrl 和 childCtrl 所建立的子作用域,這其中 childCtrl 產生的作用域又是 parentCtrl 的子作用域。
清單3. 作用域的繼承實例

<body data-ng-app="app">
 <div data-ng-controller="parentCtrl">
<input data-ng-model="args">
<div data-ng-controller="childCtrl">
 <input data-ng-model="args">
</div>
 </div>
</body>
登入後複製

   

繼承作用域符合JavaScript 的原型繼承機制,這意味著如果我們在子作用域中存取一個父作用域中定義的屬性,JavaScript 首先在子作用域中尋找該屬性,沒找到再從原型鏈上的父作用域中尋找,如果還沒找到會再往上一級原型鏈的父作用域尋找。在 AngularJS 中,作用域原型鏈的頂端是$rootScope,AnguarJS 將會尋找到$rootScope 為止,如果還是找不到,則會回傳 undefined。
我們用實例程式碼說明下這個機制。首先,我們探討下對於原型資料型態的作用域繼承機制:
清單4. 作用域繼承實例-原始型別資料繼承

<script type="text/javascript">
 angular.module(&#39;app&#39;, [])
 .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
 $scope.args = &#39;IBM DeveloperWorks&#39;;
 }])
 .controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
 }]);
</script>
<body data-ng-app="app">
 <div data-ng-controller="parentCtrl">
 <input data-ng-model="args">
<div data-ng-controller="childCtrl">
 <input data-ng-model="args">
</div>
 </div>
</body>
登入後複製

   

運行頁面,我們得到以下的結果:
圖1. 頁面執行結果。

詳解JavaScript的AngularJS框架中的作用域與資料綁定

这个结果我们非常好理解,虽然在 childCtrl 中没有定义具体的 args 属性,但是因为 childCtrl 的作用域继承自 parentCtrl 的作用域,因此,AngularJS 会找到父作用域中的 args 属性并设置到输入框中。而且,如果我们在第一个输入框中改变内容,内容将会同步的反应到第二个输入框:
图 2. 改变第一个输入框的内容后页面运行结果

詳解JavaScript的AngularJS框架中的作用域與資料綁定

假如我们修改第二个输入框的内容,此时会发生什么事情呢?答案是第二个输入框的内容从此将不再和第一个输入框的内容保持同步。在改变第二个输入框的内容时,因为 HTML 代码中 model 明确绑定在 childCtrl 的作用域中,因此 AngularJS 会为 childCtrl 生成一个 args 原始类型属性。这样,根据 AngularJS 作用域继承原型机制,childCtrl 在自己的作用域找得到 args 这个属性,从而也不再会去寻找 parentCtrl 的 args 属性。从此,两个输入框的内容所绑定的属性已经是两份不同的实例,因此不会再保持同步。

图 3.改变第二个输入框的内容后页面运行结果

詳解JavaScript的AngularJS框架中的作用域與資料綁定

假如我们将代码做如下修改,结合以上两个场景,思考下会出现怎样的结果?
清单 5. 作用域继承实例-对象数据继承

<script type="text/javascript">
angular.module(&#39;app&#39;, [])
 .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
 $scope.args = {};
 $scope.args.content = &#39;IBM DeveloperWorks&#39;;
}])
.controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
}]);
</script>
<body data-ng-app="app">
 <div data-ng-controller="parentCtrl">
 <input data-ng-model="args.content">
 <div data-ng-controller="childCtrl">
 <input data-ng-model="args.content">
 </div>
 </div>
</body>
登入後複製

答案是无论改变任何一个输入框的内容,两者的内容始终同步。
根据 AngularJS 的原型继承机制,如果 ng-model 绑定的是一个对象数据,那么 AngularJS 将不会为 childCtrl 创建一个 args 的对象,自然也不会有 args.content 属性。这样,childCtrl 作用域中将始终不会存在 args.content 属性,只能从父作用域中寻找,也即是两个输入框的的变化其实只是在改变 parentCtrl 作用域中的 args.content 属性。因此,两者的内容始终保持同步。
我们再看一个例子,这次请读者自行分析结果。
清单 6. 作用域继承实例-不再访问父作用域的数据对象。

<script type="text/javascript">
 angular.module(&#39;app&#39;, [])
 .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
 $scope.args = {};
 $scope.args.content = &#39;IBM DeveloperWorks&#39;;
}])
.controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
 $scope.args = {};
 $scope.args.content = &#39;IBM DeveloperWorks&#39;;
}]);
</script>
<body data-ng-app="app">
 <div data-ng-controller="parentCtrl">
 <input data-ng-model="args.content">
 <div data-ng-controller="childCtrl">
 <input data-ng-model="args.content">
 </div>
 </div>
</body>
登入後複製

答案是两个输入框的内容永远不会同步。
孤立作用域(Isolate Scope)
孤立作用域是 AngularJS 中一个非常特殊的作用域,它只在 directive 中出现。在对 directive 的定义中,我们添加上一个 scope:{} 属性,就为这个 directive 创建出了一个隔离作用域。
清单 7. directive 创建出一个孤立作用域

angular.module(&#39;isolate&#39;, []).directive("isolate", function () {
 return {
 scope : {},
 };
})
登入後複製

孤立作用域最大的特点是不会原型继承其父作用域,对外界的父作用域保持相对的独立。因此,如果在定义了孤立作用域的 AngularJS directive 中想要访问其父作用域的属性,则得到的值为 undefined。代码如下:
清单 8. 孤立作用域的隔离性

<script type="text/javascript">
 angular.module(&#39;app&#39;, [])
 .controller(&#39;ctrl&#39;, [&#39;$scope&#39;, function($scope) {
 $scope.args = {};
 }])
 .directive("isolateDirective", function () {
 return {
 scope : {},
 link : function($scope, $element, $attr) {
 console.log($scope.$args); //输出 undefined
 }
 };
});
</script>
<body data-ng-app="app">
 <div data-ng-controller="ctrl">
 <div data-isolate-directive></div>
 </div>
</body>
登入後複製

上面的代码中通过在 directive 中声明了 scope 属性从而创建了一个作用域,其父作用域为 ctrl 所属的作用域。但是,这个作用域是孤立的,因此,它访问不到父作用域的中的任何属性。存在这样设计机制的好处是:能够创建出一些列可复用的 directive,这些 directive 不会相互在拥有的属性值上产生串扰,也不会产生任何副作用。
AngularJS 孤立作用域的数据绑定
在继承作用域中,我们可以选择子作用域直接操作父作用域数据来实现父子作用域的通信,而在孤立作用域中,子作用域不能直接访问和修改父作用域的属性和值。为了能够使孤立作用域也能和外界通信,AngularJS 提供了三种方式用来打破孤立作用域“孤立”这一限制。
单向绑定(@ 或者 @attr)
这是 AngularJS 孤立作用域与外界父作用域进行数据通信中最简单的一种,绑定的对象只能是父作用域中的字符串值,并且为单向只读引用,无法对父作用域中的字符串值进行修改,此外,这个字符串还必须在父作用域的 HTML 节点中以 attr(属性)的方式声明。
使用这种绑定方式时,需要在 directive 的 scope 属性中明确指定引用父作用域中的 HTML 字符串属性,否则会抛异常。示例代码如下:
清单 9. 单向绑定示例

<script>
 angular.module(&#39;isolateScope&#39;, [])
 .directive("isolateDirective", function () {
 return {
 replace : true,
 template: &#39;<button>{{isolates}}</button>&#39;,
 scope : {
 isolates : &#39;@&#39;,
 },
 link : function($scope, $element, $attr) {
 $scope.isolates = "DeveloperWorks";
 }
 };
 })
 .controller("ctrl", function ($scope) {
 $scope.btns = &#39;IBM&#39;;
 });
</script>
<body data-ng-app="isolateScope" >
<div data-ng-controller="ctrl">
 <button>{{btns}}</button>
 <div data-isolate-directive data-isolates="{{btns}}"></div>
 </div>
</body>
登入後複製

简单分析下上面的代码,通过在 directive 中声明了 scope:{isolates:'@'} 使得 directive 拥有了父作用域中 data-isolates 这个 HTML 属性所拥有的值,这个值在控制器 ctrl 中被赋值为'IBM'。所以,代码的运行结果是页面上有两个名为 IBM 的按钮。
我们还注意到 link 函数中对 isolates 进行了修改,但是最终不会在运行结果中体现。这是因为 isolates 始终绑定为父作用域中的 btns 字符串,如果父作用域中的 btns 不改变,那么在孤立作用域中无论怎么修改 isolates 都不会起作用。
引用绑定(&或者&attr)
通过这种形式的绑定,孤立作用域将有能力访问到父作用域中的函数对象,从而能够执行父作用域中的函数来获取某些结果。这种方式的绑定跟单向绑定一样,只能以只读的方式访问父作用函数,并且这个函数的定义必须写在父作用域 HTML 中的 attr(属性)节点上。
这种方式的绑定虽然无法修改父作用域的 attr 所设定的函数对象,但是却可以通过执行函数来改变父作用域中某些属性的值,来达到一些预期的效果。示例代码如下:
清单 10. 引用绑定示例

<script>
 angular.module(&#39;isolateScope&#39;, [])
 .directive("isolateDirective", function () {
 return {
 replace : true,
 scope : {
 isolates : &#39;&&#39;,
 },
 link : function($scope, $element, $attr) {
 var func = $scope.isolates();
 func();
 }
 };
 })
 .controller("ctrl", function ($scope) {
 $scope.func = function () {
 console.log("IBM DeveloperWorks");
 }
 });
</script>
<body data-ng-app="isolateScope" >
 <div data-ng-controller="ctrl">
 <div data-isolate-directive data-isolates="func"></div>
 </div>
</body>
登入後複製

这个例子中,浏览器的控制台将会输出一段“IBM DeveloperWorks”文字。
上面的代码中我们在父作用域中指定了一个函数对象$scope.func,在孤立作用域中通过对 HTML 属性的绑定从而引用了 func。需要注意的是 link 函数中对 func 对象的使用方法,$scope.isolates 获得的仅仅是函数对象,而不是调用这个对象,因此我们需要在调用完$scope.isolates 之后再调用这个函数,才能得到真正的执行结果。
双向绑定(=或者=attr)
双向绑定赋予 AngularJS 孤立作用域与外界最为自由的双向数据通信功能。在双向绑定模式下,孤立作用域能够直接读写父作用域中的属性和数据。和以上两种孤立作用域定义数据绑定一样,双向绑定也必须在父作用域的 HTML 中设定属性节点来绑定。
双向绑定非常适用于一些子 directive 需要频繁和父作用域进行数据交互,并且数据比较复杂的场景。不过,由于可以自由的读写父作用域中的属性和对象,所以在一些多个 directive 共享父作用域数据的场景下需要小心使用,很容易引起数据上的混乱。
示例代码如下:
清单 11. 双向绑定示例

<script>
 angular.module(&#39;isolateScope&#39;, [])
 .directive("isolateDirective", function () {
 return {
 replace : true,
 template: &#39;<button>{{isolates}}</button>&#39;,
 scope : {
 isolates : &#39;=&#39;,
 },
 link : function($scope, $element, $attr) {
 $scope.isolates.ibm = "IBM";
 }
 };
 })
 .controller("ctrl", function ($scope) {
 $scope.btns = {
 ibm : &#39;ibm&#39;,
 dw : &#39;DeveloperWorks&#39;
 };
 });
</script>
<body data-ng-app="isolateScope" >
 <div data-ng-controller="ctrl">
 <button>{{btns.dw}}</button>
 <button>{{btns.ibm}}</button>
 <div data-isolate-directive data-isolates="btns"></div>
 </div>
</body>
登入後複製

   

上面的代码运行的结果是浏览器页面上出现三个按钮,其中第一个按钮标题为“DeveloperWorks”,第二和第三个按钮的标题为“IBM”。
初始时父作用域中的$scope.btns.ibm 为小写的“ibm”,通过双向绑定,孤立作用域中将父作用域的 ibm 改写成为大写的“IBM”并且直接生效,父作用域的值被更改。

总结
由于 AngularJS 框架的轻量性和其清晰的 MVC 特点使得其在推出之后就大受欢迎,实践中也很容易上手。AngularJS 比较难以掌握和理解的就是其作用域和绑定机制,本文重点将作用域和绑定机制做了分析与讨论,希望读者能够理解并熟练掌握这块内容。

更多詳解JavaScript的AngularJS框架中的作用域與資料綁定相关文章请关注PHP中文网!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:社區,圖書館和資源 Python vs. JavaScript:社區,圖書館和資源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

See all articles