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


Posted in Javascript onJanuary 13, 2017

 就我对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>

显示结果如下:

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

分析:从数据流向说起,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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript document.compatMode兼容性
Feb 23 Javascript
JSON.parse 解析字符串出错的解决方法
Jul 08 Javascript
jQuery实现表头固定效果的实例代码
May 24 Javascript
扩展jQuery对象时如何扩展成员变量具体怎么实现
Apr 25 Javascript
JavaScript模块化开发之SeaJS
Dec 13 Javascript
7个jQuery最佳实践
Jan 12 Javascript
浅析jquery与checkbox的checked属性的问题
Apr 27 Javascript
JS 通过系统时间限定动态添加 select option的实例代码
Jun 09 Javascript
vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能
Nov 16 Javascript
js实现鼠标切换图片(无定时器)
Jan 27 Javascript
Vue如何清空对象
Mar 03 Vue.js
vue代码分块和懒加载非必要资源文件
Apr 11 Vue.js
微信小程序 MD5加密登录密码详解及实例代码
Jan 12 #Javascript
很棒的一组js图片轮播特效
Jan 12 #Javascript
微信小程序 页面跳转传递值几种方法详解
Jan 12 #Javascript
微信小程序 详解Page中data数据操作和函数调用
Jan 12 #Javascript
百度地图API之百度地图退拽标记点获取经纬度的实现代码
Jan 12 #Javascript
js实现微博发布小功能
Jan 12 #Javascript
基于jQuery实现照片墙自动播放特效
Jan 12 #Javascript
You might like
一个典型的PHP分页实例代码分享
2011/07/28 PHP
php错误级别的设置方法
2013/06/17 PHP
php全角字符转换为半角函数
2014/02/07 PHP
php打包压缩文件之ZipArchive方法用法分析
2016/04/30 PHP
PHP实现的同步推荐操作API接口案例分析
2016/11/30 PHP
datePicker——日期选择控件(with jquery)
2007/02/20 Javascript
通过javascript获取iframe里的值示例代码
2013/06/24 Javascript
XMLHttpRequest处理xml格式的返回数据(示例代码)
2013/11/21 Javascript
QQ空间顶部折页撕开效果示例代码
2014/06/15 Javascript
第八篇Bootstrap下拉菜单实例代码
2016/06/21 Javascript
jQuery插件扩展extend的简单实现原理
2016/06/24 Javascript
JavaScript编写一个贪吃蛇游戏
2017/03/09 Javascript
js实现图片放大展示效果
2017/08/30 Javascript
jquery-file-upload 文件上传带进度条效果
2017/11/21 jQuery
微信小程序实现手势图案锁屏功能
2018/01/30 Javascript
mpvue小程序仿qq左滑置顶删除组件
2018/08/03 Javascript
微信小程序城市选择及搜索功能的方法
2019/03/22 Javascript
vue数据响应式原理知识点总结
2020/02/16 Javascript
javascript实现贪吃蛇经典游戏
2020/04/10 Javascript
python计算N天之后日期的方法
2015/03/31 Python
python简单分割文件的方法
2015/07/30 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
2018/04/02 Python
pandas中去除指定字符的实例
2018/05/18 Python
使用python将图片按标签分入不同文件夹的方法
2018/12/08 Python
python计算Content-MD5并获取文件的Content-MD5值方式
2020/04/03 Python
Python的历史与优缺点整理
2020/05/26 Python
Python3交互式shell ipython3安装及使用详解
2020/07/11 Python
selenium3.0+python之环境搭建的方法步骤
2021/02/01 Python
Wiggle美国:英国骑行、跑步、游泳、铁人三项商店
2018/10/27 全球购物
介绍一下linux文件系统分配策略
2012/11/17 面试题
表彰先进集体通报
2014/01/12 职场文书
书香校园活动方案
2014/02/28 职场文书
少先大队干部竞选稿
2015/11/20 职场文书
幼儿园大班开学寄语(2016秋季)
2015/12/03 职场文书
宪法宣传标语100条
2019/10/15 职场文书
SQLServer2019 数据库环境搭建与使用的实现
2021/04/08 SQL Server