angular directive详解
来源:互联网 发布:python 多次try 编辑:程序博客网 时间:2024/05/22 00:46
在前端开发的过程中,很多时候我们都希望能够重复的使用某一个模块,比如说文件上传、组织架构树等,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.htmlName: {{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'
- 同时匹配属性、元素和样式名称。
.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.jsangular.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.htmlName: {{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.jsangular.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 canceling timeoutId = $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.jsangular.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.jsangular.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'})">×</a> <div ng-transclude></div></div>
展示结果:
×
在上面的示例中,当我们点击×,通过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.jsangular.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 content event.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.jsangular.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.htmldiv class="tab-pane" ng-show="selected" ng-transclude></div>
当我们在directive中使用require属性,如果没有找到指定的controller,$compile将会报错,^前缀指明在父controller中寻找,没有^前缀则在自己的元素中查找。如果directive中指定了require属性,那么可以在其link方法中将该controller作为第四个参数传入。如果需要多个controller,那么require属性后面可以跟一个数组,同样link方法的第四个参数传入也是一个数组,
传入需要的controller列表。
- angular directive详解
- angular directive详解之transclude
- angular directive详解之replace
- angular directive详解之scope
- angular 自定义指令详解 Directive
- angular 自定义指令 Directive(详解)
- angular 自定义指令详解 Directive
- angular directive详解之replace
- angular 自定义指令详解 Directive
- angular directive
- angular directive
- angular directive中scope:{}
- angular scope of directive
- Angular directive 递归渲染
- Angular directive bug
- angular directive的使用
- angular directive 总结
- angular directive简介
- 1000以内水仙花数(嵌套循环)
- 关于string中涉及到的暂存池
- 动态库和静态库的区别
- hdu 1271 整数对 详解
- 简单的P2P电影下载加速,(类似迅雷下载电影P2P加速)
- angular directive详解
- python模块:调用系统命令模块subprocess等
- Error: The spatial references do not match
- 源码网站,挥泪分享啊
- 开关翻转 Gym100712I Bahosain and Digits
- android-flip FlipView出现闪烁的问题
- Android Studio 在活动中使用Toast
- 【linux】ubuntu14.04安装eclipse4.5
- 高精度取模(模板)