AngularJSAngularJs之Scope作用域

前言:

上篇博文AngularJs之directive中说了Scope功用域是个大坑,所以拿出来作为主要总计!

什么是scope

  AngularJS
中,作用域是一个针对应用模型的目标,它是表明式的推行环境。效能域有层次结构,那些层次和呼应的
DOM 大致是相同的。成效域能监控表达式和传递事件。

  在
HTML 代码中,一旦一个 ng-app 指令被定义,那么一个功能域就暴发了,由
ng-app
所生成的效用域相比卓绝,它是一个根成效域($rootScope),它是其余具有$Scope
的最顶层。

  除了用
ng-app 指令可以发生一个效率域之外,其余的授命如 ng-controller,ng-repeat
等都会时有发生一个依旧七个作用域。其它,仍能够经过 AngularJS
提供的创导成效域的厂子方法来创制一个功用域。那几个功用域都持有和谐的延续上下文,并且根功能域都为$rootScope。

  在变化一个作用域之后,在编辑
AngularJS 代码时,$scope
对象就象征了这些功用域的数目实体,我们可以在$scope
内定义种种数据类型,之后方可平素在 HTML 中以 {{变量名}} 方式来让 HTML
访问到那一个变量。

继承成效域

  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 的子成效域。

以身作则一:成效域的接轨实例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module('app', [])
            .controller('parentCtrl', ['$scope', function($scope) {
                $scope.args= 'Nick DeveloperWorks';
            }])
            .controller('childCtrl', ['$scope', function($scope) {
                $scope.args= 'Nick DeveloperWorks for test';
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args">
    <div ng-controller="childCtrl">
        <input ng-model="args">
    </div>
</div>
</body>
</html>

  继承成效域符合
JavaScript
的原型继承机制,那表示一旦大家在子成效域中做客一个父功能域中定义的属性,JavaScript
首先在子作用域中找找该属性,没找到再从原型链上的父作用域中寻找,即便还没找到会再往上一级原型链的父成效域寻找。在
AngularJS 中,功用域原型链的顶端是$rootScope,AnguarJS
将会寻找到$rootScope 停止,就算如故找不到,则会回去 undefined。

  咱们用实例代码表达下那个机制。首先,我们商量下对于原型数据类型的功效域继承机制:

以身作则二:功能域继承实例-原始类型数据继续

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module('app', [])
            .controller('parentCtrl', ['$scope', function($scope) {
                $scope.args = 'Nick DeveloperWorks';
            }])
            .controller('childCtrl', ['$scope', function($scope) {
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args">
    <div ng-controller="childCtrl">
        <input ng-model="args">
    </div>
</div>
</body>
</html>

测试运行结果:

首先个输入框:

  纵然在
childCtrl 中绝非定义具体的 args 属性,不过因为 childCtrl 的功效域继承自
parentCtrl 的效用域,因而,AngularJS 会找到父功用域中的 args
属性并设置到输入框中。而且,如若大家在首先个输入框中改变内容,内容将会同步的影响到第三个输入框。

第三个输入框:

  首个输入框的情节从此将不再和第四个输入框的始末保持同步。在改变第三个输入框的内容时,因为
HTML 代码中 model 明确绑定在 childCtrl 的意义域中,因而 AngularJS 会为
childCtrl 生成一个 args 原始类型属性。那样,按照 AngularJS
功能域继承原型机制,childCtrl 在大团结的功能域找得到 args
那一个特性,从而也不再会去找寻 parentCtrl 的 args
属性。从此,八个输入框的内容所绑定的质量已经是两份不相同的实例,因而不会再保持同步。

现将代码做如下修改,结合以上七个现象,见面世什么的结果?

示范三:功能域继承实例-对象数据继续

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module('app', [])
            .controller('parentCtrl', ['$scope', function($scope) {
                $scope.args = {};
                $scope.args.content = 'Nick DeveloperWorks';
            }])
            .controller('childCtrl', ['$scope', function($scope) {
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args.content">
    <div ng-controller="childCtrl">
        <input ng-model="args.content">
    </div>
</div>
</body>
</html>

测试结果是无论改变任何一个输入框的情节,两者的始末平素同步。

  依照AngularJS 的原型继承机制,若是 ng-model 绑定的是一个目的数据,那么
AngularJS 将不会为 childCtrl 创立一个 args 的目的,自然也不会有
args.content 属性。那样,childCtrl 功能域元帅始终不会存在 args.content
属性,只可以从父作用域中找寻,也即是两个输入框的的变更莫过于只是在转移
parentCtrl 功能域中的 args.content
属性。由此,两者的始末平昔维持同步。

  大家再看一个事例,分析结果什么。

以身作则四:作用域继承实例-不再访问父效能域的数额对象。

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module('app', [])
            .controller('parentCtrl', ['$scope', function($scope) {
                $scope.args = {};
                $scope.args.content = 'Nick DeveloperWorks';
            }])
            .controller('childCtrl', ['$scope', function($scope) {
                $scope.args = {};
                $scope.args.content = 'Nick DeveloperWorks for test';
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args.content">
    <div ng-controller="childCtrl">
        <input ng-model="args.content">
    </div>
</div>
</body>
</html>

  测试结果是七个输入框的始末永远不会一起。子作用域有实例数据对象,则不访问父效能域。

独自效用域

  独立成效域是
AngularJS 中一个要命独特的成效域,它只在 directive 中出现。在对
directive 的概念中,大家添加上一个 scope:{} 属性,就为这些 directive
创制出了一个切断作用域。

示范5: directive 创设出一个孤立功能域

angular.module('isolate', []).directive("isolate", function () {
 return {
 scope : {},
 };
})

  独立功用域最大的表征是不会原型继承其父功能域,对外场的父效能域保持相对的独自。因而,即便在概念了孤立效率域的
AngularJS directive 中想要访问其父成效域的特性,则赢得的值为
undefined。代码如下:

示例六:独立功能域的隔离性

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module('app', [])
            .controller('ctrl', ['$scope', function($scope) {
                $scope.args = {};
            }])
            .directive("isolateDirective", function () {
                return {
                    scope : {},
                    link : function($scope, $element, $attr) {
                        console.log($scope.$args); //输出 undefined
                    }
                };
            });
</script>
<body ng-app="app">
<div ng-controller="ctrl">
    <div isolate-directive></div>
</div>
</body>
</html>

  上边的代码中经过在
directive 中宣称了 scope 属性从而开创了一个功用域,其父功效域为 ctrl
所属的功用域。可是,那个效用域是孤立的,因而,它访问不到父成效域的中的任何性质。存在那样设计编制的利益是:可以创立出有些列可复用的
directive,那几个 directive
不会相互在所有的属性值上发出串扰,也不会时有暴发任何副效率。

AngularJS 独立成效域的数码绑定

  在后续作用域中,大家可以选拔子成效域直接操作父成效域数据来促成父子成效域的通信,而在独立成效域中,子功用域无法一贯访问和改动父功效域的特性和值。为了可以使孤立成效域也能和外围通讯,AngularJS
提供了二种艺术用来打破独立成效域“孤立”这一限制。

一头绑定(@ 或者 @attr)

  那是
AngularJS
独立功能域与外场父成效域进行数据通讯中最简易的一种,绑定的对象只可以是父成效域中的字符串值,并且为单向只读引用,不可能对父功用域中的字符串值举行改动,别的,那么些字符串还非得在父作用域的
HTML 节点中以 attr(属性)的办法宣示。

  使用那种绑定方式时,要求在
directive 的 scope 属性中有目共睹指定引用父成效域中的 HTML
字符串属性,否则会抛极度。示例代码如下:

实例七: 单向绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module('isolateScope', [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    template: '<button>{{isolates}}</button>',
                    scope : {
                        isolates : '@',
                    },
                    link : function($scope, $element, $attr) {
                        $scope.isolates = "DeveloperWorks";//无效
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.btns = 'NICK';
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <button>{{btns}}</button>
    <div isolate-directive isolates="{{btns}}"></div>
</div>
</body>
</html>

  上面的代码,通过在
directive 中扬言了 scope:{isolates:’@’} 使得 directive 拥有了父作用域中
data-isolates (isolates为自定义属性,不加data也得以,但提议加上data)这么些HTML 属性所独具的值,这几个值在支配器 ctrl
中被赋值为’nick’。所以,代码的运行结果是页面上有多少个名为
nick的按钮。

  我们还留意到
link 函数中对 isolates
进行了修改,可是最终不会在运转结果中反映。那是因为 isolates
始终绑定为父效率域中的 btns 字符串,如若父功用域中的 btns
不更改,那么在孤立成效域中不管怎么修改 isolates 都不会起效果。

引用绑定(&或者&attr)

  通过那种样式的绑定,孤立功效域将有力量访问到父功能域中的函数对象,从而可以实施父功效域中的函数来取得某些结果。那种措施的绑定跟单向绑定一样,只好以只读的办法访问父作用函数,并且那么些函数的定义必须写在父效用域
HTML 中的 attr(属性)节点上。

  那种方法的绑定就算无法修改父功能域的
attr
所设定的函数对象,可是却得以透过实施函数来改变父功用域中某些品质的值,来达到一些预料的功能。示例代码如下:

示例八:引用绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module('isolateScope', [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    scope : {
                        isolates : '&',
                    },
                    link : function($scope, $element, $attr) {
                        var func = $scope.isolates();
                        func();
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.func = function () {
                    console.log("Nick DeveloperWorks");
                }
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <div isolate-directive data-isolates="func"></div>
</div>
</body>
</html>

  这一个事例中,浏览器的控制台将会打印“尼克DeveloperWorks”文字。

  上边的代码中大家在父功效域中指定了一个函数对象$scope.func,在孤立成效域中通过对
HTML 属性的绑定从而引用了 func。须要专注的是 link 函数中对 func
对象的使用办法,$scope.isolates
得到的但是是函数对象,而不是调用这几个目的,由此我们必要在调用完$scope.isolates
之后再调用这一个函数,才能赢得实在的实施结果。

双向绑定(=或者=attr)

双向绑定赋予
AngularJS
孤立作用域与外面最为自由的双向数据通讯功用。在双向绑定情势下,孤立功效域可以直接读写父成效域中的属性和数量。和上述两种孤立成效域定义数据绑定一样,双向绑定也务必在父成效域的
HTML 中设定属性节点来绑定。

双向绑定万分适用于部分子
directive
须求反复和父功用域进行多少交互,并且数据相比较复杂的气象。可是,由于可以随意的读写父作用域中的属性和对象,所以在有些八个directive
共享父成效域数据的光景下要求小心使用,很不难引起数据上的糊涂。

示范代码如下:

示例九:双向绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module('isolateScope', [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    template: '<button>{{isolates}}</button>',
                    scope : {
                        isolates : '=',
                    },
                    link : function($scope, $element, $attr) {
                        $scope.isolates.name = "NICK";
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.btns = {
                    name : 'nick',
                    dw : 'DeveloperWorks'
                };
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <button>{{btns.dw}}</button>
    <button>{{btns.name}}</button>
    <div isolate-directive data-isolates="btns"></div>
</div>
</body>
</html>

  上面的代码运行的结果是浏览器页面下面世多少个按钮,其中第四个按钮标题为“DeveloperWorks”,第二和第多个按钮的标题为“NICK”。

起来时父效能域中的$scope.btns.name为小写的“nick”,通过双向绑定,孤立效能域校官父成效域的
name改写成为大写的“NICK”并且一直生效,父功用域的值被转移。

  推荐:那篇关于功效域的篇章也写的不利,可以看看!

 

相关文章