AngularJS  Directive 自定义指令(我最喜欢AngularJs的功能之一)

一:什么时候我们会用到directive

1.使html更具语义化,不用深入了解研究代码的逻辑便可知道大致逻辑。

  2.抽象出一个自定义组件,可以重复使用。

二:directive的定义及其使用方法

    1.下面是一个directive参数详细模板

angular.module('app',[]);//申明一个调用angularjs块 

angular.module('app').directive('directiveName', function factory() { 

 var directiveDefinitionObject = {
  priority: 0,
   restrict:'A',
  template: '<div></div>',
  templateUrl: 'directive.html',
  replace: false,
  transclude: false,
  scope: false,
  compile: function compile(tElement, tAttrs, transclude) {
    return {
      pre: function preLink(scope, iElement, iAttrs, controller) { ... },
      post: function postLink(scope, iElement, iAttrs, controller) { ... }
    }
  },
  link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
});

  2.参数详解

priority:

    (数字),可选参数,指明指令的优先级,若在单个DOM上有多个指令,则优先级高的先执行;

   terminal:

    (布尔型),可选参数,值为true或false,若设置为true,则优先级低于此指令的其他指令则无效,不会被调用(优先级相同的还是会执行);

restrict:

(字符串)可选参数,指明指令在DOM里面以什么形式被声明;

    取值有:E(元素),A(属性),C(类),M(注释),其中默认值为A;当然也可以两个一起用,比如EA.表示即可以是元素也可以是属性。

    E(元素):<directiveName></directiveName>  
    A(属性):<div directiveName='expression'></div>  
    C(类): <div class='directiveName'></div>  
    M(注释):<--directive:directiveName expression-->  
    一般情况下E/A/C用得比较多。

  template:

    (字符串或函数),可选参数

    例:(1)字符串时:  

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<hello-world></hello-world>
</body>
<script type="text/javascript">
angular.module('app', []);
angular.module.('app').directive('helloWorld', function() {
return {
restrict: 'E',
template: '<div><h1>Hi I am hello world.</h1></div>',
replace: true
};
});
</script>
</html>

   (2)函数时:有两个参数tElement和tAttrs

      tElement:使用此指令的元素

       tAttrs:该指令元素上的属性

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<hello-world></hello-world>
<hello-world2 title = 'I am a Hello World 2.'></hello-world2>
</body>
<script type="text/javascript">
angular.module('app', []);
app.directive('helloWorld', function() {
return {
restrict: 'E',
template: '<div><h1>Hi I am a Hello Worl.</h1></div>',
replace: true
};
});
app.directive("helloWorld2",function(){
return{
restrict:'EAC',
template: function(tElement,tAttrs){
var _html = '';
_html += '<div>'+tAttrs.title+'</div>';
return _html;
}
};
});
</script>
</html>

  templateUrl:

    (字符串或者函数)可选参数

    字符串:代表HTML文件路径的字符串

    函数:可接收两个参数tElement和tAttrs(大致同上)

    (PS:由于加载html模板是通过异步加载的,若加载大量的模板会拖慢网站的速度,所以我们可以先缓存模板)

    例:(把要加载的页面 先加载好 包含在你需要的html里)    

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<hello-world></hello-world>
</body>
<script type="text/javascript">
angular.module('app', []);
angular.module("app").directive('helloWorld', function() {
return {
restrict: 'E',
templateUrl: 'hello.html',
replace: true
};
});
</script>
<script type='text/ng-template' id='hello.html'>
<div><h1>Hi I am Hello world.</h1></div>
</script>
</html>

还有一种方法:

angular.module("app").run(["$templateCache", function($templateCache) {
$templateCache.put("hello.html",
"<div><h1>Hi I am Hello world.</h1></div>");
}]);

  replace:

    (布尔值):默认值是false. true:替换掉指令即(<hello-world></hello-world>),false:不替换

  transclude:(是否想要指令内部的内容被模板替换掉)

    (布尔值):默认值是false. true:需要和ng transclude一起使用

    例:template:"<div>hello every <div ng-transclude></div></div>"

     这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了<div>hello every <div>这是指令内部的内容</div></div>。

  scope:

    1)默认值false。表示继承父作用域;(继承不隔离)

    2)true。表示继承父作用域,并创建自己的作用域(子作用域);(继承隔离)

    3){}。表示创建一个全新的隔离作用域;(不继承隔离)

    (PS:当你想要创建一个可重用的组件时隔离作用域是一个很好的选择,通过隔离作用域我们确保指令是‘独立'的,并可以轻松地插入到任何HTML app中,并且这种做法防止了父作用域被污染;)

    下面针对隔离作用域进行详细讲解:

       a.隔离作用域怎样去访问父作用域:

       Directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互.

      1). @ 

        (用来访问 directive 外部环境定义的字符串值,主要是通过 directive 所在的标签属性绑定外部字符串值。这种绑定是单向的,即父 scope 的绑定变化,directive 中的 scope 的属性会同步变化,                                     而隔离 scope 中的绑定变化,父 scope 是不知道的。)PS:相当于继承隔离

        scope:{

        name:"@"

        }     

      2). &

        (& 方式提供一种途经是 directive 能在父 scope 的上下文中执行一个表达式。当 directive 中有什么动作需要更新到父 scope 中的时候,可以在父 scope 上下文中执行一段代码或者一个函数。PS:即绑定的是方法)

        

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<div ng-controller="myController">
<div>父scope:
<div>Say:{{value}}</div>
</div>
<div>隔离scope:
<div isolated-directive action="click()"></div>
</div>
</div>
</body>
<script type="text/javascript">
angular.module('app', []);
app.controller("myController", function ($scope) {
$scope.value = "hello world";
$scope.click = function () {
$scope.value = Math.random();
};
}).directive("isolatedDirective", function () {
return {
scope: {
action: "&"
},
template: '<input type="button" value="在directive中执行父scope定义的方法" ng-click="action()"/>'
}
})
</script>
</html>

      3). =

       (通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定。
        意思是,当你想要一个双向绑定的属性的时候,你可以使用=来引入外部属性。无论是改变父 scope 还是隔离 scope 里的属性,父 scope 和隔离 scope 都会同时更新属性值,因为它们是双向绑定的关系。)

      例:

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<div ng-controller="myController">
<div>父scope:
<div>Say:{{user.name}}<br>改变父scope的name:<input type="text" value="" ng-model="userBase.name"/></div>
</div>
<div>隔离scope:
<div isolated-directive user="userBase"></div>
</div>
</div>
</body>
<script type="text/javascript">
angular.module('app', []);
angular.module.("app").controller("myController", function ($scope) {
$scope.userBase = {
name: 'hello',
id: 1
};
}).directive("isolatedDirective", function () {
return {
scope: {
user: "="
},
template: 'Say:{{user.name}} <br>改变隔离scope的name:<input type="buttom" value="" ng-model="user.name"/>'
}
})
</script>
</html>

  controller:

    (可以是一个字符串或者函数)

    

angular.module('app', [])
angular.module.("app").directive('myDirective', function() {
restrict: 'A',
controller: 'DefinitionController'
})
// 应用中其他的地方,可以是同一个文件或被index.html包含的另一个文件
angular.module('app')
.controller('DefinitionController', function($scope, $element, $a
也可以直接在指令内部的定义为匿名函数,同样我们可以再这里注入任何服务($log,$timeout等等) js:
angular.module('app',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
}
});

另外还有一些特殊的服务(参数)可以注入

(1)$scope,与指令元素相关联的作用域

(2)$element,当前指令对应的 元素

(3)$attrs,由当前元素的属性组成的对象

(4)$transclude,嵌入链接函数,实际被执行用来克隆元素和操作DOM的函数

注意: 除非是用来定义一些可复用的行为,一般不推荐在这使用。
         指令的控制器和link函数(后面会讲)可以进行互换。区别在于,控制器主要是用来提供可在指令间复用的行为但link链接函数只能在当前内部指令中定义行为,且无法再指令间复用。

   

<!DOCTYPE html>
<html lang="zh" ng-app="app">
<head>
<meta charset="UTF-8">
<title>AngularJS入门学习</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<hello mycolor ="red">I am Hello World.</hello>
</body>
<script type="text/javascript">
angular.module('app', []);
angular.module("app").directive('hello', function() {
return {
restrict: 'EA',
transclude: true, //注意此处必须设置为true
controller:
function ($scope, $element,$attrs,$transclude,$log) { //在这里你可以注入你想注入的服务
$transclude(function (clone) {
var a = angular.element('<p>');
a.css('color', $attrs.mycolor);
a.text(clone.text());
$element.append(a);
});
$log.info("hello everyone");
}
};
});
</script>
</html>

  这里如果我们想要实用的父作用域:$scope.$parent

                               新的作用域:$scope.$parent.new()

  controllerAs

    设置控制器的别名(angular1.2给我们带来的新的语法糖)

例:

<script>
angular.module('app',[]).directive('myDirective', function () {
return {
restrict: 'EA',
transclude: true,
controller:'someController',
controllerAs:'mainController'
//..其他配置
};
});
</script>

  require

    字符串或数组

      字符串代表另一个指令的名字,作为link函数的第四个参数。假设现在我们要编写两个指令,两个指令中的link链接函数中存在有很多重合的方法,这时候我们就可以将这些重复的方法写在第三个指令的controller中(上面也讲到controller经常用来提供指令间的复用行为)然后在这两个指令中,require这个拥有controller字段的的指令(第三个指令),最后通过link链接函数的第四个参数就可以引用这些重合的方法了。

    例

<!doctype html>
<html ng-app="app">
<head>
<script src="angular.min.js"></script>
</head>
<body>
<outer-directive>
<inner-directive></inner-directive>
<inner-directive2></inner-directive2>
</outer-directive>
<script>
angular.module('app', []);
angular.module("app").directive('outerDirective', function() {
return {
scope: {},
restrict: 'AE',
controller: function($scope) {
this.say = function(someDirective) {
console.log('Show:' + someDirective.message);
};
}
};
});
angular.module("app").directive('innerDirective', function() {
return {
scope: {},
restrict: 'AE',
require: '^outerDirective',
link: function(scope, elem, attrs, controllerInstance) {
scope.message = "Hi,I am Ruby.";
controllerInstance.say(scope);
}
};
});
app.directive('innerDirective2', function() {
return {
scope: {},
restrict: 'AE',
require: '^outerDirective',
link: function(scope, elem, attrs, controllerInstance) {
scope.message = "Hi,I am Hello World.";
controllerInstance.say(scope);
}
};
}); </script> </body>
</html>

    require参数有四种:   

      1)没有前缀,指令会在自身提供的控制器中进行查找,如果找不到任何控制器,则会抛出一个error

      2)?如果在当前的指令没有找到所需的控制器,则会将null传给link连接函数的第四个参数

      3)^如果在当前的指令没有找到所需的控制器,则会查找父元素的控制器

      4)?^组合

  compile function

    function compile(tElement, tAttrs, transclude) { ... }

    编译函数用来修改模板dom的(不常用)

    需要用到编译函数例如:ngTrepeat;ngView(需要异步载入内容的)。

    各参数意义:

    tElement - template element 该指令所在的元素。

      tAttrs - template attributes 指令元素上所声明的属性。

    transclude - 一个嵌入的链接函数function(scope, cloneLinkingFn)。

    注意:在编译函数里面不要进行任何DOM变形之外的操作。 更重要的,DOM监听事件的注册应该在链接函数中做,而不是编译函数中。 编译函数可以返回一个对象或者函数。 返回函数 - 等效于在编译函数不存在时,使用配置对象的link属性注册的链接函数。 返回对象 - 返回一个通过pre或post属性注册了函数的对象。参考下面pre-linking和post-liking函数的解释。

  link function

    function link(scope, iElement, iAttrs, controller) { ... }
    链接函数负责注册DOM事件和更新DOM。它是在模板被克隆之后执行的,它也是大部分指令逻辑代码编写的地方。
    scope - 指令需要监听的作用域。
    iElement - instance element - 指令所在的元素。只有在postLink函数中对元素的子元素进行操作才是安全的,因为那时它们才已经全部链接好。
    iAttrs - instance attributes - 实例属性,一个标准化的、所有声明在当前元素上的属性列表,这些属性在所有链接函数间是共享的。
    controller - 控制器实例,也就是当前指令通过require请求的指令someDirective内部的controller。比如:someDirective指令中的controller:function(){this.Say = function(){}},那么,在当前指令的link函数中,你就可以通过controller.Say进行调用了。
    Pre-linking function 在子元素被链接前执行。不能用来进行DOM的变形,以防链接函数找不到正确的元素来链接。
    Post-linking function 所有元素都被链接后执行。

  compile function 和 link function需要注意的地方:两者是互斥的,compile function负责对模板dom进行修改,link function负责将作用域和dom进行连接。

                          当两者共存时,compile function返回的函数当作link function,link function则被忽略。

  

    

 

  

  

  

    

AngularJS 讲解,四 Directive的更多相关文章

  1. AngularJs学习笔记--directive

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/directive Directive是教HTML玩一些新把戏的途径.在DOM编译期间,directiv ...

  2. AngularJS进阶(四十)创建模块、服务

    AngularJS进阶(四十)创建模块.服务 学习要点 使用模块构架应用 创建和使用服务 为什么要使用和创建服务与模块? 服务允许你打包可重用的功能,使之能在此应用中使用. 模块允许你打包可重用的功能 ...

  3. angularjs中的directive scope配置

    angularjs中的directive scope配置 定义directive其中重要的一环就是定义scope,scope有三种形式: 默认的scope,DOM元素上原有的scope scope: ...

  4. AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template

    .controller('HomeController', function($scope,$location) { $scope.userName='天下大势,为我所控!'; $scope.clkU ...

  5. angularJs中自定义directive的数据交互

    首先放官方文档地址:https://docs.angularjs.org/guide/directive 就我对directive的粗浅理解,它一般用于独立Dom元素的封装,应用场合为控件重用和逻辑模 ...

  6. angularjs自定义指令Directive

    今天学习angularjs自定义指令Directive.Directive是一个非常棒的功能.可以实现我们自义的的功能方法. 下面的例子是演示用户在文本框输入的帐号是否为管理员的帐号"Adm ...

  7. AngularJS中有关Directive的汇总

    本篇通过几个例子对AngularJS中的Directive进行汇总. 例子1,单向绑定和双向绑定 <html ng-app="myApp"> <head> ...

  8. AngularJS自定义指令directive:scope属性 (转载)

    原文地址:http://blog.csdn.net/VitaLemon__/article/details/52213103 一.介绍: 在AngularJS中,除了内置指令如ng-click等,我们 ...

  9. angularjs 指令(directive)详解(2)

    原文地址 上一篇我们说到了transclude,那么,我们现在继续讲解之后的内容. 9.scope 可选参数,默认值为false.取值: false - 在这个directive里不会创建新的scop ...

随机推荐

  1. c语言scanf详解

    函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]);scanf()函数是通用终端格式化输入函数,它从标准输入设备(键 ...

  2. PARTITION BY 和 group by

    sum()   over   (PARTITION   BY   ...)   是一个分析函数.   他执行的效果跟普通的sum   ...group   by   ...不一样,它计算组中表达式的累 ...

  3. 单独谈谈 Android Cursor 的使用细节

    使用过 SQLite 数据库对 Cursor 应该不陌生,这里单独拿出来谈一下,加深对Android SQLite中使用 Cursor 的理解. 在你理解和使用 Android Cursor 的时候你 ...

  4. 读《Ext.JS.4.First.Look》随笔

    Ext JS 4是最大的改革已经取得了Ext框架.这些变化包括一个新类系统,引入一个新的平台,许多API变化和改进,和新组件,如新图表和新画组件.Ext JS 4是更快,更稳定,易于使用.(注意:Ex ...

  5. 把Wordpress集成到zen-cart里方法 各种修改 经典机制

    作者: 闻庭牛 | 分类: zen cart插件精解 | 浏览: 4 | 评论: 暂时没有评论 如果你的Zen-cart需要一个Blog来发布一些你的最新动态,可以试试Wordpress,并且用WOZ ...

  6. jq判断元素是否显示

    为了判断元素是否显示,jquery中用is()来实现, $(function(){ $(obj).bind('click',function(){ if(obj.is(:visible)){ //编写 ...

  7. Cisco 绑定mac地址

    在Cisco中有以下三种方案可供选择,方案1和方案2实现的功能是一样的,即在具体的交换机端口上绑定特定的主机的MAC地址(网卡硬件地址),方案3是在具体的交换机端口上同时绑定特定的主机的MAC地址(网 ...

  8. TCP/IP网络协议栈(转载)

    原文:http://www.cnblogs.com/xuanku/p/tcpip.html TCP/IP网络协议栈分为四层, 从下至上依次是: 链路层 其实在链路层下面还有物理层, 指的是电信号的传输 ...

  9. 【floyd】 poj 2240

    #include <iostream> #include <map> #include <string> #include <memory.h> usi ...

  10. HDU 1887 Weird Numbers(负数的进制转化)

    题目要求有两种情况,第一种from情况,正常输出即可,很简单.第二种是to情况,给一个数字,输出负进制R的原码,这个有点小麻烦...解决方法如下; 首先,把这个数n按正常方式展开,形式如下: .... ...