详解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 相关文章推荐
页面加载完成后再执行JS的jquery写法以及区别说明
Feb 22 Javascript
javascript学习笔记--数字格式类型
May 22 Javascript
jQuery获取动态生成的元素示例
Jun 15 Javascript
JavaScript中的函数重载深入理解
Aug 04 Javascript
Javascript保存网页为图片借助于html2canvas库实现
Sep 05 Javascript
微信小程序开发之大转盘 仿天猫超市抽奖实例
Dec 08 Javascript
JS验证字符串功能
Feb 22 Javascript
jquery网页加载进度条的实现
Jun 01 jQuery
详谈表单格式化插件jquery.serializeJSON
Jun 23 jQuery
js实现导航跟随效果
Nov 17 Javascript
详解ES6 export default 和 import语句中的解构赋值
May 28 Javascript
layui+SSM的数据表的增删改实例(利用弹框添加、修改)
Sep 27 Javascript
微信小程序 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 文件状态缓存带来的问题
2008/12/14 PHP
PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等)
2014/04/21 PHP
php实现的递归提成方案实例
2015/11/14 PHP
Laravel6.2中用于用户登录的新密码确认流程详解
2019/10/16 PHP
Z-Blog中用到的js代码
2007/03/15 Javascript
jquery $.ajax入门应用二
2008/11/19 Javascript
jQuery ui 1.7更新小结
2009/08/15 Javascript
JQuery 拾色器插件发布-jquery.icolor.js
2010/10/20 Javascript
利用jq让你的div居中的好方法分享
2013/11/21 Javascript
js和jQuery设置Opacity半透明 兼容IE6
2016/05/24 Javascript
全面解析JavaScript中apply和call以及bind(推荐)
2016/06/15 Javascript
利用JS提交表单的几种方法和验证(必看篇)
2016/09/17 Javascript
jquery实现多次上传同一张图片
2017/01/09 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
用 Vue.js 递归组件实现可折叠的树形菜单(demo)
2017/12/25 Javascript
一个因@click.stop引发的bug的解决
2019/01/08 Javascript
微信小程序实现联动选择器
2019/02/15 Javascript
vue2配置scss的方法步骤
2019/06/06 Javascript
ES6小技巧之代替lodash
2019/06/07 Javascript
Python中的作用域规则详解
2015/01/30 Python
python自动格式化json文件的方法
2015/03/11 Python
总结Python中逻辑运算符的使用
2015/05/13 Python
Python实现多属性排序的方法
2018/12/05 Python
python实现读取excel文件中所有sheet操作示例
2019/08/09 Python
tensorflow实现二维平面模拟三维数据教程
2020/02/11 Python
python 实现批量图片识别并翻译
2020/11/02 Python
python利用appium实现手机APP自动化的示例
2021/01/26 Python
让ie浏览器成为支持html5的浏览器的解决方法(使用html5shiv)
2014/04/08 HTML / CSS
美体小铺瑞典官方网站:The Body Shop瑞典
2018/01/27 全球购物
房地产销售员的自我评价分享
2013/12/04 职场文书
劳动竞赛活动总结
2014/05/05 职场文书
村主任当选感言
2015/08/01 职场文书
Golang二维切片初始化的实现
2021/04/08 Golang
简单总结SpringMVC拦截器的使用方法
2021/06/28 Java/Android
小程序实现侧滑删除功能
2022/06/25 Javascript