指令(Directive),是AngularJS中一块比较重要的内容,在实践中,我们提倡将控制器(Controller)写得短小精悍,逻辑代码尽量少,要实现这种目的,我们主要通过将逻辑代码抽取到服务(Service)和指令中实现。

  今天主要介绍一下指令的相关内容。

  一、作用、目的

  指令,本质上就是AngularJS扩展具有自定义功能的HTML元素的途径,AngularJS已经实现了很多内置指令,我们也可以通过自定义指令定制自己所需要的HTML元素,从而简化应用,并使自己的架构、代码更优雅,另一方面,由于AngularJS拥有自己的生命周期,很多插件在AngularJS应用中往往会显示“不好用”,这时候,就需要我们自己实现指令,对插件进行集成,例如,在工作中我们团队就对echarts和highcharts进行了集成。

  二、定义语法

  在AngularJS中,允许我们使用.directive() 方法定义指令, 我们可以通过传入一个字符串和一个函数来注册一个新指令。其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,函数应该返回一个对象,该对象定义了我们指令的细节。
  注:1、驼峰命名风格用来将一个短语写在一个单词中,除了第一个单词外其他单词首字母大写,中间不加空格。例如, cute boy 用驼峰风格来写应该是cuteBoy。
  注:2、在HTML里使用 my-directive声明指令,指令定义必须以myDirective为名字。如下

<my-directive></my-directive>
angular.module('myApp', [])
.directive('myDirective', function() {
// 指令定义对象
return {
// 省略...
});

  directive() 方法可以接受两个参数:
  1. name(字符串)

  指令的名字,用来在视图中引用特定的指令。
  2. factory_function (函数)

  这个函数返回一个对象,其中定义了指令的全部行为。

  对象的可选设置如下:  

angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) (...},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or
function(scope, element, attrs, transclude, otherInjectables) { ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile: // 返回一个对象或连接函数,如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
// 或者
return function postLink(...) { ... }
}
};
});
  • restrict(字符串)  

  restrict是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默认AngularJS认为restrict的值是A,即以属性的形式来进行声明。

  可选值如下:

    E(元素)  <my-directive></my-directive>
    A(属性,默认值)  <div my-directive="expression"></div>
    C(类名)  <div class="my-directive:expression;"></div>
    M(注释)  <--directive:my-directive expression-->
  这些选项可以单独使用,也可以混合在一起使用:restrict: 'EA' // 输入元素或属性

  属性是用来声明指令最常用的方式,因为它能在包括老版本的IE浏览器在内的所有浏览器中正常工作,并且不需要在文档头部注册新的标签。

  注:1、尽量避免用注释方式来声明属性。这种方式最初被用来声明由多个标签组成的指令。这种方法在某些情况下特别有用,比如在<table> 元素内使用 ng-repeat指 令 , 但 在 AngularJS 1.2 中 ng-repeat 可 以 通 过 ng-repeat-start 和ng-repeat-end来更优雅地满足这个需求,注释模式就没有什么用武之地了。

  • priority(数值型)  

  优先级参数可以被设置为一个数值。大多数指令会忽略这个参数,使用默认值0,但也有些场景设置高优先级是非常重要甚至是必须的。优先级高的指令先于其他指令调用。如果一个元素上具有两个优先级相同的指令,声明在前面的那个会被优先调用。

  • terminal (布尔型)

  terminal 是一个布尔型参数,可以被设置为true或false。这个参数用来告诉AngularJS停止运行当前元素上比本指令优先级低的指令。但同当前指令优先级相同的指令还是会被执行。

  • template(字符串或函数)  

   template参数是可选的,必须被设置为以下两种形式之一:

    一段HTML文本;
    一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串。 tElement和tAttrs中的t代表template,是相对于instance的。模板元素或属性与实例元素或属性之间是有区别的。AngularJS会同处理HTML一样处理模板字符串。模板中可以通过大括号标记来访问作用域,例如{{ expression }} 。如果模板字符串中含有多个DOM元素,或者只由一个单独的文本节点构成,那它必须被包含在一个父元素内。换句话说,必须存在一个根DOM。

template: '\
<div> <-- single root element -->\
  <a href="http://google.com">Click me</a>\
  <h1>When using two elements, wrap them in a parent element</h1>\
</div>\

  注意每一行末尾的反斜线,这样AngularJS才能正确解析多行字符串。在实际生产中,更好的选择是使用templateUrl参数引用外部模板,因为多行文本阅读和维护起来都是一场噩梦。

  • templateUrl (字符串或函数)

  templateUrl 是可选的参数,可以是以下类型:
     一个代表外部HTML文件路径的字符串;
    一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串。
  无 论 哪 种 方 式 , 模 板 的 URL 都 将 通 过 AngularJS 内 置 的 安 全 层 , 特 别 是 $getTrustedResourceUrl ,这样可以保护模板不会被不信任的源加载。
  默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件。有两件事情需要知道。
    在本地开发时,需要在后台运行一个本地服务器,用以从文件系统加载HTML模板,否则会导致Cross Origin Request Script( CORS)错误。
    模板加载是异步的,意味着编译和链接要暂停,等待模板加载完成。通过Ajax异步加载大量的模板将严重拖慢一个客户端应用的速度。为了避免延迟,可以在部署应用之前对HTML模板进行缓存。在大多数场景下缓存都是一个非常好的选择,因为AngularJS通过减少请求数量提升了性能。模板加载后, AngularJS会将它默认缓存到$templateCache服务中。在实际生产中,可以提前将模板缓存到一个定义模板的JavaScript文件中。

  • replace(布尔型)  

  replace是一个可选参数,如果设置了这个参数,值必须为true,因为默认值为false。默认值意味着模板会被当作子元素插入到调用此指令的元素内部。

  • scope参数(布尔型或对象)  

  scope参数是可选的,可以被设置为true或一个对象。默认值是false。

  当scope设置为true时,会从父作用域继承并创建一个新的作用域对象。

  当scope设置为一个对象,则创建了一个隔离作用域。如果一个元素上有多个指令使用了隔离作用域,其中只有一个可以生效。只有指令模板中的根元素可以获得一个新的作用域。因此,对于这些对象来说scope默认被设置为true。

  AngularJS提供了几种方法能够将指令内部的隔离作用域,同指令外部的作用域进行数据绑定。

  @ (or @attr)@ (or @attr)@本地作用域属性:使用@符号将本地作用域同DOM属性的值进行绑定。指令内部作用域可以使用外部作用域的变量:
  =双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。就像普通的数据绑定一样,本地属性会反映出父数据模型中所发生的改变。
  &父级作用域绑定 通过&符号可以对父级作用域进行绑定,以便在其中运行函数。意味着对这个值进行设置时会生成一个指向父级作用域的包装函数。

  • transclude(布尔型)

  transclude(嵌入)是一个可选的参数。如果设置了,其值必须为true,它的默认值是false。用以包含任意内容。

  我们可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。这样做可以将任意内容和作用域传递给指令。 transclude参数就是用来实现这个目的的,指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象。
  注:1、只有当你希望创建一个可以包含任意内容的指令时, 才使用 transclude: true。

  注:2、如果指令使用了transclude参数,那么在控制器中就无法正常监听数据模型的变化了。这就是最佳实践总是建议在链接函数里使用$watch服务的原因。

  未完待续

AngularJS 指令(Directivce )一的更多相关文章

  1. AngularJS指令

    1. AngularJS指令的特点: AngularJS通过被称为指令的新属性来扩展HTML,指令的前缀为ng-. AngularJS通过内置的指令来为应用添加功能. AngularJS允许你自定义指 ...

  2. angularjs指令参数transclude

    angularjs指令参数transclude transclude翻译为嵌入,和之前看到的vue中的slots作用差不多,目的是将指令元素的子内容嵌入到指令的模板中 定义指令 <div sid ...

  3. angularjs 指令—— 绑定策略(@、=、&)

    angularjs 指令—— 绑定策略(@.=.&) 引入主题背景:angular 的指令配置中的template可以直接使用硬编码写相应的代码,不过也可以根据变量,进行动态更新.那么需要用到 ...

  4. AngularJS 指令

    AngularJS 指令 AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-. ng-app 指令 ng-app 指令定义了 AngularJS 应用程序的 根元素. ng-app 指 ...

  5. angularjs指令(二)

    最近学习了下angularjs指令的相关知识,也参考了前人的一些文章,在此总结下. 欢迎批评指出错误的地方.   Angularjs指令定义的API AngularJs的指令定义大致如下 angula ...

  6. angularJs指令执行的机制==大概的三个阶段

    第一阶段:加载阶段 angularJs要运行的话,需要去等待angular.js加载完成,加载完之后呢,angular就会去查找到ng-app这个指令,ng-app在每个应用里面只能出现一次, 它也就 ...

  7. AngularJS学习笔记二:AngularJS指令

    AngularJS 指令: AngularJS 通过被称为 指令 的新属性来扩展 HTML. AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-. 几个常用 指令: ng-app 指令 ...

  8. AngularJs指令(一)

    AngularJs应用现在越来越流行了,谷歌都与微软合作支持AngularJS2.0,这是要逆天了,说明AngularJs将来大势所趋.最近想跳槽,又重新拾起了AngluarJs(之前由于缺少项目应用 ...

  9. 【转】angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  10. AngularJS指令进阶 – ngModelController详解

    AngularJS指令进阶 – ngModelController详解 在自定义Angular指令时,其中有一个叫做require的字段,这个字段的作用是用于指令之间的相互交流.举个简单的例子,假如我 ...

随机推荐

  1. PAT Advanced 1154 Vertex Coloring (25 分)

    A proper vertex coloring is a labeling of the graph's vertices with colors such that no two vertices ...

  2. Educational Codeforces Round 40 C. Matrix Walk( 思维)

    Educational Codeforces Round 40 (Rated for Div. 2) C. Matrix Walk time limit per test 1 second memor ...

  3. Appium Desired Capabilities-Android Only

    Android Only These Capabilities are available only on Android-baseddrivers (like UiAutomator2for exa ...

  4. loj515 「LibreOJ β Round #2」贪心只能过样例[bitset+bool背包]

    由于bitset极其不熟练且在实际题目中想不起来运用它来优化,于是练了几道题. 这题是一个分组的bool背包,每组必须选一个,暴力的话是$O(n^5)$. 如果dp数组不要一维滚动的话,有两种枚举方法 ...

  5. redis cluster 介绍

    介绍 1. cluster的作用 (1)自动将数据进行分片,每个master上放一部分数据 (2)提供内置的高可用支持,部分master不可用时,还是可以继续工作的 2. redis集群实现方案 关于 ...

  6. C#主菜单动态添加子菜单并设置触发事件

    我所使用的是devxepress中的主菜单栏时barsubitem控件,想的是在其能够动态添加子菜单栏并能点击触发事件: /// <summary> /// 创建主按钮的子按钮 /// & ...

  7. 2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018) D. Delivery Delays (二分+最短路+DP)

    题目链接:https://codeforc.es/gym/101933/problem/D 题意:地图上有 n 个位置和 m 条边,每条边连接 u.v 且有一个距离 w,一共有 k 个询问,每个询问表 ...

  8. BZOJ 1283: 序列 (最大费用流)

    题意 有n个正整数,要选取里面的一些数,在保证每m个连续的数中最多选k个的情况下,使得得到的值最大. 分析 我们可以把问题先转化为选k次,每一次每m个数只能选一个.那么根据贪心的策略,每m个里一定会选 ...

  9. 在maven项目中如何引入另外一个项目(转)

    原文链接:https://blog.csdn.net/jianfpeng241241/article/details/52654352 1  在Myeclipse中准备两个maven demo. , ...

  10. 题解 noip2019模拟赛Day1T3

    题面 运河计划 问题描述 水运在人类的交通运输史中一直扮演着重要的角色.借助河流.的便利,人们得以把大量的货物输送到天南海北不仅仅是自然界现成的河流,人工开凿的运河(如苏伊士运河.巴拿马运河.我国的京 ...