angulajs 详解 directive 中 的 scope 概念

   Directive 是 angularjs 中最重要的概念,我的理解就是自定义html tag, 这个自定的tag 浏览器不会解析,会有angularjs 来动态解析。

 

   比如在html 中添加 <myPannel title="title" description="pannel description"></mypanel>, 这个myPannel tag 浏览器显然不认识,这个其实就是一个 directive. 这个directive 我们必须在js 代码中进行定义并且为其设置显示的html模板,才能让其正常在页面中显示。

   本文将假设你已经知道directive 的概念,并且知道如何创建一个自定义的directive. 对于这部分内容,本文不做介绍,本文主要介绍在自定义directive 中一个非常重要的属性 scope.

   在angularjs 启动的时候,会自动创建一个rootScope 对象。 创建controller和directive 的时候,会自动创建自己的私有scope对象,私有scope从rootScope继承. 

   Directive 中的scope 

 所有的directives 都有自己的 scope 对象。 在默认的情况下,directive  不会创建他们自己的scope. 他们会用他们父对象的scope作为自己的scope.  但是 angularjs 允许改变这种默认行为。

   比如下面的列子:   

var app = angular.module("myAPP",[]);

app.directive("mySpan",function(){

  return {

      restrict: "EA",

      scope: true,

      link: function(scope,elem,attr){

          

      }

  }    

 });

上面的代码我们创建一个名字为mySpan的directive. 里面有个scope 属性,我们设置值为 true. 这个属性,可以设置为下列值中的一个,true, flase 或者{}.

下面我们将接受这三个值得不同。

Directive scope 取值不同的区别

scope : false (Directives 将使用parent 的scope), 这个是默认值

看下面的列子:

1. html 代码

<div ng-app="myapp">

    

    <div ng-controller="Ctrl1">

        <h2 ng-click="changeName()">Hey {{name}}, Click me to reinit name</h2>

        <div my-directive class='directive'></div>

    </div>

</div>

2.  Js 代码

var app = angular.module("myapp",[]);



app.controller("Ctrl1",function($scope){

    $scope.name = "Slardar";

    $scope.changeName = function(){

       $scope.name += "_";

    };

});

app.directive("myDirective", function(){

    return {

        restrict: "EA",

        scope: false,

        template: "<div>Your name is : {{name}}</div>"+

        "Change your name : <input type='text' ng-model='name' />"

    };

});

3. css

h2 {

    cursor: pointer;

}

.directive {

    border: 5px solid #F5BF6E;

    padding: 10px;

}

 

预览地址: http://jsfiddle.net/od3a4ddw/9/

可以看到,在directive 里面的name 属性和controller 里面的name是一个对象。也就是说directive 使用了其parent 的scope 对象作为自己的scope对象。当在controller 中 改变name 对象的值时,directive 的name 会更新, 反之在directive 中更新name 属性,controller 里面的name 也会更新。 因为他们其实是一个对象。

 

scope : true(Directives 会创建一个新的scope,但是创建的这个scope 将从parent controller 中的 scope 对象继承。)

 当设为false的时候,directive 会使用parent 对象的scope 对象, 设为为true 会创建一个scope 对象,但是从parent 的scope 对象继承。 这两句话,好像有点不好理解。

我们修改上面的js 代码,将scope 对象设为true

var app = angular.module("myapp",[]);



app.controller("Ctrl1",function($scope){

    $scope.name = "Slardar";

    $scope.changeName = function(){

        $scope.name +='_';

    };

});

app.directive("myDirective", function(){

    return {

        restrict: "EA",

        scope: true,

        template: "<div>Your name is : {{name}}</div>"+

        "Change your name : <input type='text' ng-model='name' />"

    };

});

预览地址: http://jsfiddle.net/od3a4ddw/10/

点击 里面的header, 可以看到在directive 里面的name 和controller 中的name 同时在改变 (也就是说在这个时候,directive 里面name 对象是从parent 对象直接获取到的(继承的原因)。但是当我们在directive 里面的textbox 输入的时候,发现对name 对象的修改不再影响 parentscope 的name 属性。 这是因为, directive 里面的name 对象是在 text box 里面的 onchange 事件后触发的创建的。也就是说directive 在text onchange 事件发生后创建了自己的name 对象。 同时在这个时候 再次点击header 发现directive 里面的name 值不再受到parent scope 中name 的影响。

 

Scope : {}(Directives 会创建一个新的隔离scope,这个隔离的scope 不从parent scope对象继承)

这个官方推荐的写scope 的方式, 这样就避免的directive 中的对象和parent 的对象相互影响,但是由于创建的新的隔离对象是个全新的空对象,因为为这个对象赋值就变成了一个问题。

看下面的列子:

修改js 代码如下

var app = angular.module("myapp",[]);



app.controller("Ctrl1",function($scope){

    $scope.name = "Slardar";

    $scope.changeName = function(){

        $scope.name += "-";

    };

});

app.directive("myDirective", function(){

    return {

        restrict: "EA",

        scope: {},

        template: "<div>Your name is : {{name}}</div>"+

        "Change your name : <input type='text' ng-model='name' />"

    };

});

 

预览地址 :http://jsfiddle.net/qggdk7gg/

从上面的列子可以看到,点击header 文字的时候,direct里面name 始终未空,这是因为directive 里面的scope 是个隔离的scope, 它对parent的scope变量一无所知。

但是我们可以通过下面的方式将值从parent 对象中传递到 directive 中。

传值有以下三种方式:

 通过 @ 传值  (字符串绑定,one way binding(单向绑定),就是传递字符串到directive 进行显示),在调用directive 的时候,需要对 attribute 使用 {{}} 进行传值。

 通过  = 传值   (模型 绑定, two way bingding(双向绑定)) 在调用directive 的时候,需要对 attribute 使用  模型名称  进行传值。

 通过 & 传值 (方法绑定)

 下面看完整的列子:

1. html 代码

<div ng-app="app">

    

    <div class="parent" ng-controller="MainCtrl">

        <div class="line">

            Name inside parent scope is: <strong>{{name}}</strong>  

            <input type="button" ng-click="changeName()" value="Change name" />

        </div> 

        <div class="line">

            title in parent scope is: {{title}} 

            <input type="button" ng-click="changeTitle()" value="Change title" />

        </div>

        <div class="directive" my-directive

            name="{{name}}"

            title="title"

            change-name="changeName()"

        ></div>

    </div>

</div>

2. JS 代码

var app = angular.module("app", []);



app.controller("MainCtrl", function( $scope ){

    $scope.name = "Slardar";

    $scope.title = "Slardar_title";

    $scope.changeName = function(){

     $scope.name += '_';

    };

    $scope.changeTitle = function(){

     $scope.title += '_';

    }

});



app.directive("myDirective", function(){

    

    return {

        restrict: "EA",

        scope: {

            name: "@",

            title: "=",

            changeName: "&"

        },

        template: [

            "<div class='line'>",

            "Title : <strong>{{title}}</strong>;<br/>Name : <strong>{{name}}</strong>;  Change name:<input type='text' ng-model='name' /><br/>",

            "</div><div class='line'>",           

            "<br/><input type='button' ng-click='changeName()' value='Change Name'/>"

        ].join("")    

    };

});

3. Css 

.parent {

    border: 20px solid #676767;

    padding : 20px;

}

.parent,.directive {

    position: relative;

}

.parent:after,.directive:after {

    display: inline;

    color: #fff;

    font-size: normal;

    position: absolute;

    top:-20px;

    left:-20px;

    z-index: 100;

    padding: 1px 5px;

    background-color: rgba(0,0,0,0.5);

}

.parent:after {

    content: "MainCtrl Scope";

}

.directive {

    padding: 20px;

    border: 20px solid #cbccdd;

    margin-top: 20px;

}

.directive:after {

    content: "Directive Scope"

}

.line {

    border-bottom: 1px dotted #ccc;

    padding: 5px 0;

}

完整演示地址: http://jsfiddle.net/g5kdns5x/1/

上面可以 看以看到完整的directive 定义

 <div class="directive" my-directive

            name="{{name}}"

            title="title"

            change-name="changeName()"

        ></div>

 

其中 name 属性 用 @ 定义  单向字符串绑定,后面使用 {{}}进行赋值。 列子中 只是传递name 属性值在directive 中系那是。

title 用 = 定义 模型绑定, 后面使用 scope 中的属性名字。  列子中传递 title 模型到 directive 中, 在direct 中对title 模型进行修改会同步到parent 对象的title 中。

change-name 用 & 定义,方法绑定。后面直接跟方法调用。 例子中传递了changeName 方法到 directive 里面,使的在directive里面可以使用 parent 对象里面定义的changeName 方法。

 

好了,以上就是我对directive 中关于scope 定义的介绍,希望对大家的学习有所帮助。

 

你可能感兴趣的:(Directive)