首页 > 代码库 > AngularJS 指令的 Scope (作用域)

AngularJS 指令的 Scope (作用域)

每当一个指令被创建的时候,都会有这样一个选择:是继承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope)),还是创建一个新的自己的作用域。AngularJS为指令的scope参数提供了三种选择,分别是:false,true,{}。

scope = false(默认情况)

当scope参数为false时,指令模板可以直接使用父作用域中的变量,函数。
代码如下所示:

angular.module("MyApp", [])
.controller("MyController", function ($scope) {
    $scope.name = "dreamapple";
    $scope.age = 20;
    $scope.changeAge = function () {
        $scope.age = 22;
    }
})
.directive("myDirective", function () {
    var obj = {
        restrict: "AE",
        scope: false,
        replace: true,
        template: "<div class=‘my-directive‘>" +
            "<h3>下面部分是我们创建的指令生成的</h3>" +
            "我的名字是:<span ng-bind=‘name‘></span><br/>" +
            "我的年龄是:<span ng-bind=‘age‘></span>" +
            "<input type=‘text‘ ng-model=‘name‘>"+
            " </div>"
    }
    return obj;
});

HTML代码:

<div ng-app="MyApp">
    <div class="container" ng-controller="MyController">
        <div class="my-info">我的名字是:<span ng-bind="name"></span>
            <br/>我的年龄是:<span ng-bind="age"></span>
        </div>
        <div class="my-directive" my-directive></div>
    </div>
</div>

CSS代码:

div{
    padding: 6px;
}
div.container {
    border: 1px solid black;
}
div.my-info {
    border: 1px solid blue;
}
div.my-directive{
    border: 1px solid green;
}


因为我们将scope的属性设置为false,所以我们创建的指令继承了父作用域的一切属性和方法,这也使得在指令的模板中我们可以使用这些属性和方法。
-注意-:此时我们在输入框里改变名字,会发现上面的两个名字都发生了变化。

scope = true

当把scope属性设置为true时,这表明我们创建的指令要创建一个新的作用域,这个作用域初始化的时候继承父作用域。修改新建的作用域内的值,只会改变该作用域下的数据。
修改上面的JS代码,将指令中的:scope:false修改为scope:true试试效果

scope = {}

当我们将scope设置为{}时,意味着我们创建了一个新的与父作用域隔离的作用域,这使我们在不知道外部环境的情况下,就可以正常工作,不依赖外部环境。
修改上述的JS代码和HTML代码 JS代码:

angular.module("MyApp", [])
.controller("MyController", function ($scope) {
    $scope.name = "dreamapple";
    $scope.age = 20;
    $scope.changeAge = function(){
        $scope.age = 0;
    }
})
.directive("myDirective", function () {
    var obj = {
        restrict: "AE",
        scope: {
            name: ‘@myName‘,
            age: ‘=‘,
            changeAge: ‘&changeMyAge‘
        },
        replace: true,
        template: "<div class=‘my-directive‘>" +
            "<h3>下面部分是我们创建的指令生成的</h3>" +
            "我的名字是:<span ng-bind=‘name‘></span><br/>" +
            "我的年龄是:<span ng-bind=‘age‘></span><br/>" +
            "在这里修改名字:<input type=‘text‘ ng-model=‘name‘><br/>" +
            "<button ng-click=‘changeAge()‘>修改年龄</button>" +
            " </div>"
    }
    return obj;
});

HTML代码:

<div ng-app="MyApp">
    <div class="container" ng-controller="MyController">
        <div class="my-info">我的名字是:<span ng-bind="name"></span>
            <br/>我的年龄是:<span ng-bind="age"></span>
            <br />
        </div>
        <div class="my-directive" my-directive 
        my-name="{{name}}" age="age"  change-my-age="changeAge()"></div>
    </div>
</div>

我们使用了隔离的作用域,不代表我们不可以使用父作用域的属性和方法。
我们可以通过向scope的{}中传入特殊的前缀标识符(即prefix),来进行数据的绑定。
在隔离作用域内,我们可以通过@,&和=引用应用指令的元素的属性,如上面的代码那样,我们可以在<div class="my-directive" my-directive my-name="{{name}}" age="age" change-my-age="changeAge()"></div>这个元素中,利用前缀标识符通过使用属性my-name,age,change-my-age来引用这些属性的值。
下面我们来看看如何使用这些前缀标识符:

@

这是一个单项绑定的前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive my-name="{{name}}"></div>注意,属性的名字要用-将两个单词连接,因为是数据的单项绑定所以要通过使用{{}}来绑定数据。

=

这是一个双向数据绑定前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive age="age"></div>注意,数据的双向绑定要通过=前缀标识符实现,所以不可以使用{{}}。

&

这是一个绑定函数方法的前缀标识符
使用方法:在元素中使用属性,好比这样<div my-directive change-my-age="changeAge()"></div>注意,属性的名字要用-将多个个单词连接。
-注意-:在新创建指令的作用域对象中,使用属性的名字进行绑定时,要使用驼峰命名标准,比如下面的代码。

scope: {
    name: ‘@myName‘, 
    age: ‘=‘,
    changeAge: ‘&changeMyAge‘ 
}

进一步说明,我们的指令是如何利用这些前缀标识符来寻找我们想要的属性或者函数的?

@ 当指令编译到模板的name时,就会到scope中寻找是否含有name的键值对,如果存在,就像上面那样,看到@就知道这是一个单向的数据绑定,然后寻找原来的那个使用指令的元素上(或者是指令元素本身)含有这个值的属性即my-name={{name}},然后在父作用域查找{{name}}的值,得到之后传递给模板中的name。
=和&与@差不多,只不过=进行的是双向的数据绑定,不论模板还是父作用域上的属性的值发生改变都会使另一个值发生改变,而&是绑定函数而已。

AngularJS 指令的 Scope (作用域)