directive的嵌套

来源:互联网 发布:桌面便签软件 编辑:程序博客网 时间:2024/06/03 19:24

AngularJS实现组件化的方法主要是通过directive,用template属性或templateUrl属性引入独立的组件视图,用scope创建独立的作用域。
对于directive的scope属性,已经由很多讲解得很详细的文章了,所以这里不再赘述,而是讨论一下当directive嵌套时的scope是如何与controller中的scope进行绑定的。

之前看了一篇文章http://www.csdn123.com/html/topnews201408/92/6292.htm,也是讲嵌套的directive的作用域。文中特别提到了在DOM结构上嵌套的directive在作用域上并不会嵌套。我想也没想就信了,然后就出了一个两个小时的BUG,直接付出了一次熬夜的代价。

其实“directive的嵌套”应该有两种理解。
注:在下文中,所有提到的“独立作用域”都表示scope: {}

第一种情况

假设有这样的DOM结构,myGrid、myRow、myCell三个指令层层嵌套。

<div ng-controller="TestController">    <my-grid>        <my-row>            <my-cell input="input" lock="lock"></my-cell>        <my-row>    </my-grid></div>

刚才提到的那篇文章说的就是这种情况,当三个指令全部使用独立作用域是,它们的的scope的$parent全部指向TestController的$scopoe。当然,如果有哪个指令没有使用独立作用域,也就是scope: false,那么这个指令的scope就是其所属controller的$scope

测试代码如下:

var controller;testModule.controller("TestController", function ($scope) {    $scope.input={        a: "1",        b: "2"    };    $scope.lock=false;    controller=$scope;});var grid=testModule.directive("grid", function () {    return {        restrict: "E",        scope: {},        link: function (scope, element, attribute) {            console.log("grid: "+(scope.$parent==controller));        }    };});testModule.directive("row", function () {    return {        restrict: "E",        scope: {},        link: function (scope, element, attribute) {            console.log("row: "+(scope.$parent==controller));        }    };});testModule.directive("cell", function () {    return {        restrict: "E",        scope: {},        link: function (scope, element, attribute) {            console.log(scope.input);            console.log("cell: "+(scope.$parent==controller));        }    };});

其中用controller这个全局变量保存了TestController的$scope,输出结果如下:

Object { a: “1”, b: “2” }
cell: true
row: true
grid: true

说明在这种形式的嵌套下,嵌套的指令作用域都指向其所属的controller。

第二种情况

假设有这样一个TestController中的“parent”directive,在这个“parent”directive的HTML里又嵌套了一个“child”directive

<div ng-controller="TestController">    <parent></parent></div>

这两种情况下的指令作用域是不同的

var testModule=angular.module("TestModule", []);/*$scope中的input和lock属性用于测试*/testModule.controller("TestController", function ($scope) {    $scope.input={        a: "1",        b: "2"    };    $scope.lock=false;});/*外层的directive,parent*/testModule.directive("parent", function () {    return {        restrict: "E",        template: "<child input='input' lock='lock'></child>",        link: function (scope, element, attribute) {            console.log("parent directive");                        }    }});/*内层的directive,child,只包含了一个h1标签*/testModule.directive("child", function () {    return {        restrict: "E",        template: "<h1>It's child</h1>",        scope: {            input: "=",            lock: "="        },        link: function (scope, element, attribute) {            console.log("child directive")            console.log(scope.input);            console.log(scope.lock);        }    }});

可以看到parent指令嵌套了child指令,child指令的DOM元素上有input和lock两个属性分别与TestController中的属性进行了绑定。而在这种情况下parent指令和child指令的作用域是会发生嵌套的。

下面我会对parent指令和child指令的scope做一些修改。

上面代码中给出的情况是parent没有独立作用域,child独立了作用域并绑定了TestController的input和lock属性。
这段代码的输出如下:

child directive
Object { a: “1”, b: “2” }
false
parent directive

parent、child、controller依旧为parent指令和child指令和TestController的scope。此时:

parent==controllertruechild.$parent==controllertrue

当给parentscope: {}赋值为独立作用域后,我们再运行这段代码,会发现child指令中scope.input和scope.lock的输出都变成了undefined。这时我们再在控制台中进行测试,会发现:

parent.$parent==controllertruechild.$parent==parenttrue

这时child指令的父作用域其实就是parent的scope,因为parent的scope中什么都没有,所以input和lock属性的输出就是undefined。不同于第一种情况,在这种情况下,指令的作用域会发生嵌套。
也就是说,如果我们在外部指令使用了独立作用域,而且还想把这些外部指令与controller绑定的属性传给内部指令的话,那么内部指令就要和外部指令的对应属性进行绑定。

0 0