首先放官方文档地址:
就我对 directive 的粗浅理解,它一般用于独立 Dom 元素的封装,应用场合为控件重用和逻辑模块分离。后者我暂时没接触,但数据交互部分却是一样的。所以举几个前者的例子,以备以后忘记。
directive 本身的作用域 $scope 可以选择是否封闭,不封闭则和其 controller 共用一个作用域 $scope。例子如下:
- 1 <body ng-app="myApp" ng-controller="myCtrl">
- 2 <test-directive></test-directive>
- 3 <script>
- 4 angular.module("myApp",[])
- 5 .controller("myCtrl",function($scope){
- 6 $scope.data = {
- 7 name:"白衣如花"
- 8 };
- 9 })
- 10 .directive("testDirective",function(){
- 11 return {
- 12 restrict:"E",
- 13 template:"<h1>{{data.name||'未定义'}}</h1>"
- 14 }
- 15 });
- 16 </script>
- 17 </body>
显示结果为:白衣如花,可以知道 directive 中的 data.name 就是 myCtrl 控制器中的 $scope.data.name。
那么封闭的 directive 呢?怎么封闭,封闭效果是什么样的,封闭后怎么数据交互?这些都是我这几天摸索的东西。
- 1 <body ng-app="myApp" ng-controller="myCtrl">
- 2 <test-directive></test-directive>
- 3 <script>
- 4 angular.module("myApp",[])
- 5 .controller("myCtrl",function($scope){
- 6 $scope.data = {
- 7 name:"白衣如花"
- 8 };
- 9 })
- 10 .directive("testDirective",function(){
- 11 return {
- 12 restrict:"E",
- 13 scope: {},
- 14 template:"<h1>{{data.name||'未定义'}}</h1>"
- 15 }
- 16 });
- 17 </script>
- 18 </body>
结果显示为:未定义。所以在 directive 定义时,添加属性 scope 就可以把 directive 的作用域和父控制器的作用域分离开来。
好,了解了开放和封闭之后,进入主题,如何进行数据交互。个人觉得数据交互分为:父控制器获取 directive 的变量;directive 获取父控制器的变量;父控制器调用 directive 的函数;directive 调用父控制器的函数。
1. 父控制器获取 directive 的变量。比如封装了一个输入框接受用户输入,父控制器点击搜索按钮要获取用户输入:
- 1 < body ng - app = "myApp"ng - controller = "myCtrl" > 2 < p > 名字: {
- {
- outerName
- }
- } < /p>
- 3 <test-directive inner-name="outerName"></test - directive > 4 < script > 5 angular.module("myApp", []) 6.controller("myCtrl",
- function($scope) {
- 7
- }) 8.directive("testDirective",
- function() {
- 9
- return {
- 10 restrict: "E",
- 11 scope: {
- 12 innerName: "="13
- },
- 14 template: "<input type='text' ng-model='innerName' placeholder='白衣如花'>"15
- }
- 16
- });
- 17 < /script>
- 18 </body >
显示结果如下:
分析:从数据流向说起,testDirective 中的一个 input 输入绑定在 innerName 中,innerName 是 directive 私有作用域拥有的变量,外部控制器不能直接用。通过 innerName: "=" 传递给 html 中的 inner-name 属性,
而 inner-name 属性则绑定在外部控制器的 outerName 变量中,所以最后显示在最上面的 <p> 标签内。上述代码等价于如下代码:
- <test-directive name="outerName"></test-directive>
- scope: {
- innerName: "=name"
- },
由 inerName: "=" 变成了 innerName: "=name",而 html 属性绑定也由 inner-name 变成了 name。
2.directive 获取父控制器的变量。这个应用场合应该挺多的,比如公共的页眉页脚,公共的展示面板等。
这个用上面例子的 "=" 一样可以实现,于是我们知道了 "=" 是双向绑定。但是我们要防止 directive 内部意外修改数据该怎么办呢?于是单向绑定 "@" 就出场了。
- 1 <body ng-app="myApp" ng-controller="myCtrl">
- 2 <input type='text' ng-model='outerName' placeholder='白衣如花'>
- 3 <test-directive inner-name="{{outerName}}"></test-directive>
- 4 <script>
- 5 angular.module("myApp",[])
- 6 .controller("myCtrl",function($scope){
- 7 })
- 8 .directive("testDirective",function(){
- 9 return {
- 10 restrict:"E",
- 11 scope: {
- 12 innerName: "@"
- 13 },
- 14 template:"<p>名字:{{innerName}}</p>" +
- 15 "<button ng-click='innerName=innerName+1'>点击</button>"
- 16 }
- 17 });
- 18 </script>
- 19 </body>
值得注意的是:@在 html 的属性绑定时需要 {{}} 开标识,而 = 则不用。我的理解是,对于父控制器而言,@是数据传递,而 = 是数据绑定,所以有这些区别。directive 中加入了一个按钮用于验证修改数据后
父控制器是否发生改变,结果是 = 有变化,@无变化,很容易得出结论:= 是双向绑定,@是双向绑定。
3.directive 调用父控制器的函数。应用场合,暂时想不到(汗)。
变量用 = 和 @来传递,函数则用 &。例子如下:
- 1 < body ng - app = "myApp"ng - controller = "myCtrl" > 2 < p > 名字: {
- {
- outerName
- }
- } < /p>
- 3 <test-directive on-click="click(name)"></test - directive > 4 < script > 5 angular.module("myApp", []) 6.controller("myCtrl",
- function($scope) {
- 7 $scope.click = function(name) {
- 8 $scope.outerName = name || "白衣如花";
- 9
- }
- 10
- }) 11.directive("testDirective",
- function() {
- 12
- return {
- 13 restrict: "E",
- 14 scope: {
- 15 onClick: "&"16
- },
- 17 template: "<input type='text' ng-model='innerName' placeholder='白衣如花'>" + 18 "<button ng-click='onClick({name: innerName})'>点击</button>"19
- }
- 20
- });
- 21 < /script>
- 22 </body >
数据传递流程和之上的例子差不多,唯一要注意的是参数传递时,{name: innerName} 前者是形参,后者是实参。多个参数时,参数顺序不重要,形参一一对应。
4. 父控制器调用 directive 的函数。这个是前段时间遇到的难点,情况较其他复杂一些。应用场合也很普遍,比如初始化,重置等。
- 1 < body ng - app = "myApp"ng - controller = "myCtrl" > 2 < button ng - click = "click()" > 重置 < /button>
- 3 <test-directive action="action"></test - directive > 4 < script > 5 angular.module("myApp", []) 6.controller("myCtrl",
- function($scope) {
- 7 $scope.action = {};
- 8 $scope.click = function() {
- 9 $scope.action.reset();
- 10
- }
- 11
- }) 12.directive("testDirective",
- function() {
- 13
- return {
- 14 restrict: "E",
- 15 scope: {
- 16 action: "="17
- },
- 18 template: "<input type='text' ng-model='name' placeholder='白衣如花'>",
- 19 controller: function($scope) {
- 20 $scope.action.reset = function() {
- 21 $scope.name = "白衣如花"22
- }
- 23
- }
- 24
- }
- 25
- });
- 26 < /script>
- 27 </body >
又一次用到了 =,利用了 js 中函数也是属性的原理。似乎,理解了 = 的双向绑定,就很容易调用 directive 内部函数了。但是初始化呢?
首先想到的是类似的 = 来引用传递:
- 1 <body ng-app="myApp" ng-controller="myCtrl">
- 2 <test-directive action="action"></test-directive>
- 3 <script>
- 4 angular.module("myApp",[])
- 5 .controller("myCtrl",function($scope){
- 6 $scope.action = {};
- 7 $scope.action.init();
- 8 })
- 9 .directive("testDirective",function(){
- 10 return {
- 11 restrict:"E",
- 12 scope: {
- 13 action: "="
- 14 },
- 15 template:"<input type='text' ng-model='name' placeholder='白衣如花'>",
- 16 controller: function ($scope) {
- 17 $scope.action.init = function () {
- 18 $scope.name = "白衣如花"
- 19 }
- 20 }
- 21 }
- 22 });
- 23 </script>
- 24 </body>
但是运行却发现,错误显示 $scope.action.init is not a function,看提示应该是运行到第 7 行的时候,$scope.action.init 函数还未定义。怎么办呢?把 directive 提到 controller 之前试试?一样是错误。
嗯,可以不用函数,直接在 directive 的 controller 中执行 $scope.name = "白衣如花", 似乎很完美,但如果是有参数的初始化呢?事实上 js 分离后,我遇到的问题是根据 http 请求的返回结果来初始化 directive,由于
网络快慢不一定,导致控件初始化时不一定有 http 请求的返回(没有有效的初始化参数),也不能保证 http 请求返回后 directive 已经初始化(不能用 = 来进行函数调用)。
需求很明了了,如果能监控参数变化,再执行初始化,此时能保证 directive 已经加载,而且有有效的参数。正好 angularjs 提供了 $watch。代码如下:
- 1 <body ng-app="myApp" ng-controller="myCtrl">
- 2 <test-directive action="action"></test-directive>
- 3 <script>
- 4 angular.module("myApp",[])
- 5 .controller("myCtrl",function($scope){
- 6 $scope.action = {name: "白衣如花"};
- 7 })
- 8 .directive("testDirective",function(){
- 9 return {
- 10 restrict:"E",
- 11 scope: {
- 12 action: "="
- 13 },
- 14 template:"<input type='text' ng-model='name' placeholder='白衣如花'>",
- 15 link: function (scope, elem, attrs) {
- 16 scope.$watch(attrs.action, function (value) {
- 17 scope.action.init();
- 18 })
- 19 },
- 20 controller: function ($scope) {
- 21 $scope.action.init = function () {
- 22 $scope.name = $scope.action.name
- 23 }
- 24 }
- 25 }
- 26 });
- 27 </script>
- 28 </body>
这是我对于 directive 数据交互的粗浅理解。想要更详细了解,请参看官方文档:
来源: