在前端开发的过程中,很多时候我们都希望能够重复的使用某一个模块,比如说文件上传、组织架构树等,angular的directive可以帮助我们轻松的实现组件的重复使用。

首先先让我们解释一个问题:什么是directive?

directive是DOM元素的一个标记(可以是属性、元素名称、类名和文本内容),告诉angular的compiler给这个元素添加指定的行为,或者改变这个元素及其子元素。

angular提供了很多内置的directive(比如ngBind、ngModel和ngClass)方便我们使用,就像可以创建controller和service一样,我们也可以创建自己的directive。

下面让我们创建一个directive,这个directive仅仅用一个静态的模板替换它的内容。

index.html

<div ng-controller="Controller"><div my-customer></div>
</div>

script.js

angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {$scope.customer = {name: 'Naomi',address: '1600 Amphitheatre'};
}])
.directive('myCustomer', function() {return {template: 'Name: {{customer.name}} Address: {{customer.address}}'};
});

展示结果

Name: Naomi Address: 1600 Amphitheatre。

当然,很多时候我们要在directive中展示的内容,绝不仅仅是一个静态的文本,可能是一颗组织架构树,有着复杂的样式,这时候将html代码写在directive的template属性后就显得代码很臃肿,我们可以使用templateUrl属性,后面跟上需要加载的模板路径,例如示例所示:

index.html

<div ng-controller="Controller"><div my-customer></div>
</div>

script.js

angular.module('docsTemplateUrlDirective', [])
.controller('Controller', ['$scope', function($scope) {$scope.customer = {name: 'Naomi',address: '1600 Amphitheatre'};
}])
.directive('myCustomer', function() {return {templateUrl: 'my-customer.html'};
});

my-customer.html

Name: {{customer.name}} Address: {{customer.address}}

需要说明的是,templateUrl后面可以是一个方法,方法返回需要加载的模板路径,例如:

.directive('myCustomer', function() {return {templateUrl: function(elem, attr){return 'customer-'+attr.type+'.html';}};
});

该方法后面可以跟两个参数,elem代表匹配到directive的元素,attr代表和元素关联的对象。

当我们创建一个directive,这个directive默认按照元素和属性进行匹配,我们可以通过restrict属性进行匹配设置。

restrict 属性可以设置为:

  • 'A' - 只匹配属性名称
  • 'E' - 只匹配元素名称
  • 'C' - 只匹配样式名称

如果需要可以结合使用:

  • 'AEC' - 同时匹配属性、元素和样式名称。

下面的示例中我们指定derective仅仅根据元素名称匹配

.directive('myCustomer', function() {return {restrict: 'E',templateUrl: 'my-customer.html'};
});

我们上面的directive写的很棒,但是有一个致命的缺陷,就是我们的directive不能重复使用,换句话说,就是在一个指定的scope中,由于directive直接访问controller中的customer,所以directive替换之后的结果是一样,通过下面的示例简单说明一下:

index.html

<div ng-controller="NaomiController"><my-customer></my-customer></br><my-customer></my-customer>
</div>

展示结果:

Name: Naomi Address: 1600 Amphitheatre。

Name: Naomi Address: 1600 Amphitheatre。

解决问题的方法是将directive中的scope与外面的scope隔离,同时将需要在directive中使用的值映射到directive的scope中,我们将这种解决方法称为isolate scope,下面,我们还是通过一个示例简单演示一下:

index.html

<div ng-controller="Controller"><my-customer info="naomi"></my-customer><hr><my-customer info="igor"></my-customer>
</div>

script.js

angular.module('docsIsolateScopeDirective', [])
.controller('Controller', ['$scope', function($scope) {$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };$scope.igor = { name: 'Igor', address: '123 Somewhere' };
}])
.directive('myCustomer', function() {return {restrict: 'E',scope: {customerInfo: '=info'},templateUrl: 'my-customer-iso.html'};
});

my-customer-iso.html

Name: {{customerInfo.name}} Address: {{customerInfo.address}}

展示结果

Name: Naomi Address: 1600 Amphitheatre


Name: Igor Address: 123 Somewhere

在index.html中我们将naomi(定义在controller中:$scope.naomi)绑定在info属性上面,在我们的directive中,我们通过customerInfo: '=info',将naomi绑定到customerInfo中,因此我们可以在template中通过customerInfo访问用户信息。

scope: {// same as '=customer'customer: '='
},

这是一种简写形式,等价于customer: '=customer'。

angular的宗旨之一是将业务逻辑和页面展示分离,业务逻辑放在controller中,页面展示放在template中,controller中是不推荐直接操作DOM的,所有的DOM操作应该放在directive中进行,下面我们还是用一个简单的示例演示如何在directive中操作DOM,该示例在页面中显示一个时钟,该时钟每一秒更新一下时间。

index.html

<div ng-controller="Controller">Date format: <input ng-model="format"> <hr/>Current time is: <span my-current-time="format"></span>
</div>

script.js

angular.module('docsTimeDirective', [])
.controller('Controller', ['$scope', function($scope) {$scope.format = 'M/d/yy h:mm:ss a';
}])
.directive('myCurrentTime', ['$interval', 'dateFilter', function($interval, dateFilter) {function link(scope, element, attrs) {var format,timeoutId;function updateTime() {element.text(dateFilter(new Date(), format));}scope.$watch(attrs.myCurrentTime, function(value) {format = value;updateTime();});element.on('$destroy', function() {$interval.cancel(timeoutId);});// start the UI update process; save the timeoutId for cancelingtimeoutId = $interval(function() {updateTime(); // update DOM}, 1000);}return {link: link};
}]);

前面我们学习了可以通过isolate scope传递值或者对象供directive使用,但有些时候我们需要传递整个模板,这时候我们需要使用transclude属性选项,考虑下面代码的输出结果是什么:

index.html

<div ng-controller="Controller"><my-dialog>Check out the contents, {{name}}!</my-dialog>
</div>

script.js

angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {$scope.name = 'Tobias';
}])
.directive('myDialog', function() {return {restrict: 'E',transclude: true,scope: {},templateUrl: 'my-dialog.html',link: function (scope, element) {scope.name = 'Jeff';}};
});

my-dialog.html

<div class="alert" ng-transclude>
</div>

我们在controller和directive的link方法中都定义了name属性,根据前面讲的isolate scope的知识,似乎显示的结果应该是Jeff,但是,如果你这样想就错啦,因为transclude属性修改了scope的嵌入方式,使得在directive的内容中能够访问所有外部的scope变量而不是内部的scope变量,所以最后的显示结果为:

Check out the contents, Tobias!

下面我们在对话框中添加一个按钮,允许用户绑定特定的行为:

index.html

<div ng-controller="Controller">{{message}}<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog(message)">Check out the contents, {{name}}!</my-dialog>
</div>

script.js

angular.module('docsIsoFnBindExample', [])
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {$scope.name = 'Tobias';$scope.message = '';$scope.hideDialog = function (message) {$scope.message = message;$scope.dialogIsHidden = true;$timeout(function () {$scope.message = '';$scope.dialogIsHidden = false;}, 2000);};
}])
.directive('myDialog', function() {return {restrict: 'E',transclude: true,scope: {'close': '&onClose'},templateUrl: 'my-dialog-close.html'};
});

my-dialog-close.html

<div class="alert"><a href class="close" ng-click="close({message: 'closing for now'})">&times;</a><div ng-transclude></div>
</div>

展示结果:

×

Check out the contents, Tobias!

在上面的示例中,当我们点击×,通过ng-click调用close方法,'&'允许在directive中调用方法close,但是在close方法注册的源scope中执行,也就是在controller中执行hideDialog方法,此外可以通过键值对的形式向directive外部传递参数,如示例中所示ng-click="close({message: 'close for now'})",此时可以在hideDialog方法中访问message变量。

下面我们创建一个directive,这个directive允许用户拖拽元素,让我们以此来说明如何在directive中创建事件监听。

index.html

<span my-draggable>Drag ME</span>

script.js

angular.module('dragModule', [])
.directive('myDraggable', ['$document', function($document) {return {link: function(scope, element, attr) {var startX = 0, startY = 0, x = 0, y = 0;element.css({position: 'relative',border: '1px solid red',backgroundColor: 'lightgrey',cursor: 'pointer'});element.on('mousedown', function(event) {// Prevent default dragging of selected contentevent.preventDefault();startX = event.pageX - x;startY = event.pageY - y;$document.on('mousemove', mousemove);$document.on('mouseup', mouseup);});function mousemove(event) {y = event.pageY - startY;x = event.pageX - startX;element.css({top: y + 'px',left:  x + 'px'});}function mouseup() {$document.off('mousemove', mousemove);$document.off('mouseup', mouseup);}}};
}]);

最后让我们创建一个directive,此directive根据我们点击的tab展示不同的内容。

index.html

<my-tabs><my-pane title="Hello"><h4>Hello</h4><p>Lorem ipsum dolor sit amet</p></my-pane><my-pane title="World"><h4>World</h4><em>Mauris elementum elementum enim at suscipit.</em><p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p></my-pane>
</my-tabs>

script.js

angular.module('docsTabsExample', [])
.directive('myTabs', function() {return {restrict: 'E',transclude: true,scope: {},controller: function($scope) {var panes = $scope.panes = [];$scope.select = function(pane) {angular.forEach(panes, function(pane) {pane.selected = false;});pane.selected = true;};this.addPane = function(pane) {if (panes.length === 0) {$scope.select(pane);}panes.push(pane);};},templateUrl: 'my-tabs.html'};
})
.directive('myPane', function() {return {require: '^myTabs',restrict: 'E',transclude: true,scope: {title: '@'},link: function(scope, element, attrs, tabsCtrl) {tabsCtrl.addPane(scope);},templateUrl: 'my-pane.html'};
});

my-tabs.html

<div class="tabbable"><ul class="nav nav-tabs"><li ng-repeat="pane in panes" ng-class="{active:pane.selected}"><a href="" ng-click="select(pane)">{{pane.title}}</a></li></ul><div class="tab-content" ng-transclude></div>
</div>

my-pane.html

div class="tab-pane" ng-show="selected" ng-transclude>
</div>

当我们在directive中使用require属性,如果没有找到指定的controller,$compile将会报错,^前缀指明在父controller中寻找,没有^前缀则在自己的元素中查找。

如果directive中指定了require属性,那么可以在其link方法中将该controller作为第四个参数传入。如果需要多个controller,那么require属性后面可以跟一个数组,同样link方法的第四个参数传入也是一个数组,

传入需要的controller列表。

angular directive详解相关推荐

  1. Angular Directive 详解

    Angular Directive 学习 学习目的:为了更好的了解 ng directive 的使用方法. Directive可能是AngularJS中比较复杂的一个东西了.一般我们将其理解成指令.A ...

  2. angular路由详解

    angular路由 路由 (route) ,几乎所有的 MVC(VM) 框架都应该具有的特性,因为它是前端构建单页面应用 (SPA) 必不可少的组成部分. 那么,对于 angular 而言,它自然也有 ...

  3. Angular 变化检测详解

    作者:PingCode 产品研发部研发二组负责人王凯 前言 变化检测是前端框架中很有趣的一部分内容,各个前端的框架也都有自己的一套方案,一般情况下我们不太需要过多的了解变化检测,因为框架已经帮我们完成 ...

  4. 【精】angular.json配置详解【angular12】

    文章目录 说明 目录结构的理解 angular.json详解 说明 angular升级到6以后,我们通过脚手架创建的项目就由angular-cli.json变为了angular.json了.其中引入了 ...

  5. angularjs directive 实例 详解

    angularjs directive 实例 详解 张映 发表于 2014-03-13 前面提到了angularjs的factory,service,provider,这个可以理解成php的model ...

  6. AngularJS 详解Directive(指令)机制

    AngularJS  5个实例详解Directive(指令)机制 大漠穷秋  http://damoqiongqiu.iteye.com/blog/1917971 1.一点小说明 指令的作用:实现语义 ...

  7. backbone java_Backbone和Angular Java技术详解

    Tomcat系列之Java技术详解 将不同的思想和工具进行对比,是一种更好地理解它们的方式.在本文中,我首先将列举在创建web应用程序时需要重复进行的各项任务,随后为你展现Backbone和Angul ...

  8. angular元素属性绑定_AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用...

    AngularJS简单易学,但是功能强大.特别是在构建单页面应用方面效果显著.而 数据绑定 可以说是他被广泛使用的最主要的优点.他舍弃了对DOM的操作方式,一切都由AngularJS来自动更新视图,我 ...

  9. Angular目录结构分析以及app.module.ts详解

    场景 Angular介绍.安装Angular Cli.创建Angular项目入门教程: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detail ...

  10. angular 标准目录结构_Angular-cli新建项目目录结构详解

    Angular-cli新建项目目录结构详解 在上一篇博客中我们已经通过Angular CLI命令行工具创建出来一个全新的Angular项目,要想写项目,首先我们要先搞清楚项目的目录结构是怎样的,每个文 ...

最新文章

  1. Android之解析Android Map地图返回的Json数据
  2. 【C语言入门教程】2.7 表达式
  3. python用户输入算式并计算_Python 70行代码实现简单算式计算器
  4. 分布式 RPC架构简单理解
  5. 推荐算法炼丹笔记:阿里序列化推荐算法ComiRec
  6. linux和裸机的区别,操作系统与裸机的区别
  7. Top命令找出CPU占用较高的Java线程信息
  8. 程序员,别说你只会增删改查.....
  9. 前后端怎么连接_如何搭建前后端分离的测试平台
  10. sshd_config 配置文件
  11. javaweb面试题目整理
  12. 用javaScript实现轮播图效果 包括自动变换,按钮控制,上一张下一张切换
  13. java string的最大长度_String的长度最大是多长?
  14. 使用MOno Cecil 的相关开源项目
  15. 三维可视化与智慧消防的关系
  16. <video>标签及属性说明
  17. 大白话、最简单——SpringBoot+Mybatis+freemarker整合(二)
  18. Oracle - LOB(大对象数据类型)
  19. 阿里云视觉AI训练营_Class5_实践课:人脸动漫化搭建
  20. implementation 'com.guo.android_extend:android-extend:1.0.6'失败解决方法

热门文章

  1. python读取数据集前十行,python数据分析万字干货!一个数据集全方位解读pandas
  2. mysql table already_MySQL优化表时提示 Table is already up to date的解决方法
  3. 重磅直播 | 透彻剖析室内室外激光SLAM关键算法
  4. 技术领导力 程序员如何才能带团队 文摘 (三)
  5. 解析12306订票流程
  6. 企业要如何建立适合自己的PMF?
  7. linux磁盘连接方式,LaCie 最新的外接硬盘以 USB-C 作为连接方式
  8. 基于JavaWeb医疗管理系统的开发与实现
  9. MVP是什么,不是什么
  10. 日志:每个软件工程师应该知道的实时数据的统一抽象概念