详解angularJs中自定义directive的数据交互

就我对directive的粗浅理解,它一般用于独立Dom元素的封装,应用场合为控件重用和逻辑模块分离。后者我暂时没接触,但数据交互部分却是一样的。所以举几个前者的例子,以备以后忘记。
directive本身的作用域$scope可以选择是否封闭,不封闭则和其controller共用一个作用域$scope。例子如下:
<body ng-app="myApp" ng-controller="myCtrl">
<test-directive></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.data = {
          name:"白衣如花"
        };
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          template:"<h1>{{data.name||‘未定义‘}}</h1>"
        }
      });
</script>
</body>
显示结果为:白衣如花,可以知道directive中的data.name就是myCtrl控制器中的$scope.data.name。
  那么封闭的directive呢?怎么封闭,封闭效果是什么样的,封闭后怎么数据交互?这些都是我这几天摸索的东西。
<body ng-app="myApp" ng-controller="myCtrl">
<test-directive></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.data = {
          name:"白衣如花"
        };
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {},
          template:"<h1>{{data.name||‘未定义‘}}</h1>"
        }
      });
</script>
</body>
结果显示为:未定义。所以在directive定义时,添加属性scope就可以把directive的作用域和父控制器的作用域分离开来。
好,了解了开放和封闭之后,进入主题,如何进行数据交互。个人觉得数据交互分为:父控制器获取directive的变量;directive获取父控制器的变量;父控制器调用directive的函数;directive调用父控制器的函数。
1.父控制器获取directive的变量。比如封装了一个输入框接受用户输入,父控制器点击搜索按钮要获取用户输入:
<body ng-app="myApp" ng-controller="myCtrl">
<p>名字:{{outerName}}</p>
<test-directive inner-name="outerName"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            innerName: "="
          },
          template:"<input type=‘text‘ ng-model=‘innerName‘ placeholder=‘白衣如花‘>"
        }
      });
</script>
</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内部意外修改数据该怎么办呢?于是单向绑定"@"就出场了。
<body ng-app="myApp" ng-controller="myCtrl">
<input type=‘text‘ ng-model=‘outerName‘ placeholder=‘白衣如花‘>
<test-directive inner-name="{{outerName}}"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            innerName: "@"
          },
          template:"<p>名字:{{innerName}}</p>" +
          "<button ng-click=‘innerName=innerName+1‘>点击</button>"
        }
      });
</script>
</body>
值得注意的是:@在html的属性绑定时需要{{}}开标识,而=则不用。我的理解是,对于父控制器而言,@是数据传递,而=是数据绑定,所以有这些区别。directive中加入了一个按钮用于验证修改数据后
父控制器是否发生改变,结果是=有变化,@无变化,很容易得出结论:=是双向绑定,@是双向绑定。
 3.directive调用父控制器的函数。应用场合,暂时想不到(汗)。
变量用=和@来传递,函数则用&。例子如下:
<body ng-app="myApp" ng-controller="myCtrl">
<p>名字:{{outerName}}</p>
<test-directive on-click="click(name)"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.click = function (name) {
          $scope.outerName = name || "白衣如花";
        }
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            onClick: "&"
          },
          template:"<input type=‘text‘ ng-model=‘innerName‘ placeholder=‘白衣如花‘>" +
          "<button ng-click=‘onClick({name: innerName})‘>点击</button>"
        }
      });
</script>
</body>
数据传递流程和之上的例子差不多,唯一要注意的是参数传递时,{name: innerName}前者是形参,后者是实参。多个参数时,参数顺序不重要,形参一一对应。
4.父控制器调用directive的函数。这个是前段时间遇到的难点,情况较其他复杂一些。应用场合也很普遍,比如初始化,重置等。
<body ng-app="myApp" ng-controller="myCtrl">
<button ng-click="click()">重置</button>
<test-directive action="action"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.action = {};
        $scope.click = function () {
          $scope.action.reset();
        }
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            action: "="
          },
          template:"<input type=‘text‘ ng-model=‘name‘ placeholder=‘白衣如花‘>",
          controller: function ($scope) {
            $scope.action.reset = function () {
              $scope.name = "白衣如花"
            }
          }
        }
      });
</script>
</body>
又一次用到了=,利用了js中函数也是属性的原理。似乎,理解了=的双向绑定,就很容易调用directive内部函数了。但是初始化呢?
首先想到的是类似的=来引用传递:
<body ng-app="myApp" ng-controller="myCtrl">
<test-directive action="action"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.action = {};
        $scope.action.init();
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            action: "="
          },
          template:"<input type=‘text‘ ng-model=‘name‘ placeholder=‘白衣如花‘>",
          controller: function ($scope) {
            $scope.action.init = function () {
              $scope.name = "白衣如花"
            }
          }
        }
      });
</script>
</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。代码如下:
<body ng-app="myApp" ng-controller="myCtrl">
<test-directive action="action"></test-directive>
<script>
  angular.module("myApp",[])
      .controller("myCtrl",function($scope){
        $scope.action = {name: "白衣如花"};
      })
      .directive("testDirective",function(){
        return {
          restrict:"E",
          scope: {
            action: "="
          },
          template:"<input type=‘text‘ ng-model=‘name‘ placeholder=‘白衣如花‘>",
          link: function (scope, elem, attrs) {
            scope.$watch(attrs.action, function (value) {
              scope.action.init();
            })
          },
          controller: function ($scope) {
            $scope.action.init = function () {
              $scope.name = $scope.action.name
            }
          }
        }
      });
</script>
</body>
这是我对于directive数据交互的粗浅理解。想要更详细了解,请参看官方文档:https://docs.angularjs.org/guide/directive
时间: 2024-10-25 01:43:50

详解angularJs中自定义directive的数据交互的相关文章

详解Springboot中自定义SpringMVC配置

详解Springboot中自定义SpringMVC配置 WebMvcConfigurer接口 ? 这个接口可以自定义拦截器,例如跨域设置.类型转化器等等.可以说此接口为开发者提前想到了很多拦截层面的需求,方便开发者自由选择使用.由于Spring5.0废弃了WebMvcConfigurerAdapter,所以WebMvcConfigurer继承了WebMvcConfigurerAdapter大部分内容. WebMvcConfigurer接口中的方法 举例1:configurePathMatch配置

详解AngularJS中的依赖注入

依赖注入 一般来说,一个对象只能通过三种方法来得到它的依赖项目: 我们可以在对象内部创建依赖项目 我们可以将依赖作为一个全局变量来进行查找或引用 我们可以将依赖传递到需要它的地方 在使用依赖注入时,我们采用的是第三种方式(另外两种方式都会引起其他困难的挑战,例如污染全局作用域以及使隔离变得几乎不可能).依赖注入是一种设计模式,它移除了硬编码依赖,因此使得我们可以在运行中随时移除并改变依赖项目. 在运行过程中能够修改依赖项目的能力允许我们创建隔离环境,这对于测试来说是非常理想的.我们可以用测试环境

详解javaweb中jstl如何循环List中的Map数据_java - JAVA

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 详解javaweb中jstl如何循环List中的Map数据 第一种方式: 1:后台代码(测试) List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); Map<String, Object> map = null; for (int i = 0; i < 4; i++) { ma

CSS学习笔记(9)--详解CSS中:nth-child的用法

详解CSS中:nth-child的用法 前端的哥们想必都接触过css中一个神奇的玩意,可以轻松选取你想要的标签并给与修改添加样式,是不是很给力,它就是":nth-child". 下面我将用几个典型的实例来给大家讲解:nth-child的实际用途: Tips:还用低版本的IE浏览器的哥们请绕过! :nth-child(2)选取第几个标签,"2可以是你想要的数字" .demo01 li:nth-child(2){background:#090} :nth-child(n

实例详解 EJB 中的六大事务传播属性--转

前言 事务 (Transaction) 是访问并可能更新数据库中各种数据项的一个程序执行单元 (unit).在关系数据库中,一个事务可以是一条或一组 SQL 语句,甚至整个程序.它有通常被称为 ACID 的原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持续性(Durability)四大特性: 原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做. 一致性(Consistency):事务必须是使数据库

onLayout源码 流程 思路详解(ANDROID自定义视图)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考我之前的文章:(ANDROID自定义视图--onMeasure流程,MeasureSpec详解) 而这篇文章就来谈谈第二步:"

详解C中volatile关键字

volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化.). 例如: volatile int i=10; int j = i; ... int k = i; volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i

详解CSS中:nth-child的用法_大前端

http://www.daqianduan.com/3737.html 前端的哥们想必都接触过css中一个神奇的玩意,可以轻松选取你想要的标签并给与修改添加样式,是不是很给力,它就是":nth-child". 下面我将用几个典型的实例来给大家讲解:nth-child的实际用途: Tips:还用低版本的IE浏览器的哥们请绕过! :nth-child(2)选取第几个标签,"2可以是你想要的数字" .demo01 li:nth-child(2){background:#0

详解Java中代码块和继承

本文发表于个人GitHub主页,原文请移步详解Java中代码块和继承 阅读. 概念 1.代码块 局部代码块 用于限定变量生命周期,及早释放,提高内存利用率 静态代码块 对类的数据进行初始化,仅仅只执行一次. 构造代码块 把多个构造方法中相同的代码可以放到这里,每个构造方法执行前,首先执行构造代码块. 2.继承 继承是已有的类中派生出新的类,新的类能够吸收已有类的数据属性和行为,并能扩展新的功能. 代码块的执行顺序 public class Test {    public String name