Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >AngularJs指令解密

AngularJs指令解密

作者头像
双愚
发布于 2018-07-17 06:54:36
发布于 2018-07-17 06:54:36
2.3K00
代码可运行
举报
运行总次数:0
代码可运行

指令定义

在《AngularJs权威教程》中,指令可以简单理解成特定的DOM元素上运行的函数;我认为还可以理解成将将自定义的HTML标签解析成原始的标签,然后为其加入一些扩展的功能(函数). angularjs 提供了一个强大的扩展系统,通过指令机制,我们可以通过自定义指令来扩展自己的指令系统。

在AngularJS的核心里,指令可以绑定元素的属性(例如可见性,class列表,内部文本,内部HTML或者值)到scope的属性或表达式。最值得注意的是,一旦监测到scope中的变化被标记,这些绑定就会被更新。反过来也是相似的,使用$observe函数能够监测DOM属性,当监测到属性变化时会触发一个回调。

AngularJS应用的模块中有很多方法可以使用,其中directive()这个方法是用来定义指令的: 不急,首先要注意下指令的名字,先看个简单例子:

尽管在上面的的代码片段中我们定义了一个命名为myDirective的指令,AngularJS约定在 HTML 标记里使用破折号的形式连接名字。如果这个指令作为一个属性实现,那么我在 HTML 中就会像这样调用:<span my-directive></span>

还有:directive()方法可以接受两个参数:

  1. name(字符串) 指令的名字,用来在视力中引用特定的指令。
  2. factory_function(函数) 这个函数返回一个对象,其中定义了指令的全部行为。$compile服务利用这个方法返回的对象,在DOM调用指令时来构造指令的行为。注意:为了避免与未来的HTML标准冲突,给自定义的指令加入前缀来代表自定义的命名空间。AngularJS本身已经使用了ng-前缀,所以可以选择除此以外的名字。在例子中我们使用my-前缀(比如my-derictive)。

当AngularJS在DOM中遇到具名的指令时,会去匹配已经注册过的指令,并通过名字在注册过的对象中查找。此时,就开始了一个指令的生命周期,指令的生命周期开始于\$compile方法并结束于link方法

下面,来看看定义一个指令时可以使用的全部设置选项。 可能的选项如下所示,每个键的值说明了可以将这个属性设置为何种类型或者什么样的函数:

下面我们来详细说说每种设置

restrict(字符串string)

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 --> AE : 可以结合上面的任意值来放松限制。

  • 千万别用 ‘C’ 或者 ‘M’ 来限制你的指令。 用 ‘C’ 不能使之在标记中凸显出来, 用 ‘M’ 是为了向后兼容。 如果你觉得有趣, 你可以用一个例子来设置 restrict 为 ‘ACME’。 这些选项可以单独使用,也可以混合在一起使用。
  • 属性是用来声明指令最常用的方式,因为它能在包括老版本的IE浏览器在内的所有浏览器中正常工作,并且不需要在文档头部注册新的标签。
  • 包含某个组件的核心行为时使用元素型。用额外的行为、状态或者其他内容进行修饰或扩展时使用属性型优先级(数值型Number)
  • 优先级参数可以被设置为一个数值。大多数指令会忽略这个参数,使用默认值0,但也有些场景设置高优先级是非常重要甚至是必须的。例如,ngRepeat将这个参数设置为1000,这样就可以保证在同一元素上,它总是在其他指令之前被调用。
  • 如果一个元素上具有两个优先级相同的指令,声明在前面的那个会被优先调用。如果其中一个的优先级更高,则不管声明的顺序如何都会被优先调用:具有更高优先级的指令总是优先运行。
  • terminal(布尔型Boolean)

terminal是一个布尔型参数,可以被设置为true或false。 这个参数用来告诉AngularJS停止运行当前元素上比本指令优先级低的指令。但同当前指令优先级相同的指令还是会被执行。 如果元素上某个指令设置了terminal参数并具有较高的优先级,就不要再用其他低优先级的指令对其进行修饰了,因为不会被调用。但是具有相同优先级的指令还是会被继续调用。

template(字符串string或函数Function)

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

一段HTML文本; 一个可以接受两个参数的函数,参数为tElementtAttrs,并返回一个代表模板的字符串。tElement和tAttrs中的t代表template,是相对于instance的。在讨论链接和编译设置时会详细介绍,模板元素或属性与实例元素或属性之间的区别。

在实际生产中,更好的选择是使用templateUrl参数引用外部模板,因为多行文本阅读和维护起来都是一场噩梦。

templateUrl(字符串String | 函数Function)

可选的参数,可以是以下类型:

  • 一个代表外部HTML文件路径的字符串
  • 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串

模板的URL都将通过AngularJS内置的安全层, 特别是\$getTrustedResourceUrl,这样可以保护模板不会被不信任的源加载

调用指令时会在后台通过Ajax来请求HTML模板文件,也就是说:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
* 需要防止CORS错误
* 编译和链接要暂停,等待模板加载完成

模板加载后,AngularJS会将它默认缓存到$templateCache服务中,,可以提前将模板缓存到一个定义模板的JavaScript文件中,这样就不需要通过XHR来加载模板了

replace(布尔型Boolean)

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

调用指令之后的结果如下(这是默认replace为false时的情况):

如果replace被设置为了true:

指令调用后的结果将是:

scope(布尔值Boolean | 对象Object)

scope参数是可选的,默认为false:

  • false:直接调用相同的作用域对象;
  • true:从当前作用域对象继承一个新的作用域对象;
  • 对象:创建一个同当前作用域相隔离的作用域对象。

####独立作用域

 scope属性值设置为true,作用是让自定义的每一个指令拥有独立的作用域,而不是共享一个作用域。

隔离作用域

通常情况下,当我们需要创建可复用的组建时,我们需要的就是具有隔离作用域的指令。它不依赖于上下文或者说是父级的作用域,所以可以随意迁移,不需要考虑依赖数据的问题。  隔离作用域实现起来很简单,只要将自定义指令返回对象中“scope”值写成“{}”就行。

使用隔离作用域时,可以将指令内部的隔离作用 域,同指令外部的作用域进行数据绑定:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
* 本地作用域属性:使用@符号将本地作用域同DOM属性的值进行绑定
* 双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定
* 父级作用域绑定:通过&符号可以对父级作用域进行绑定,以便在其中运行函数

transclude(布尔值Boolean)

可选,默认为false

可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。这样做可以将任意内容和作用域传递给指令。transclude参数就是用来实现这个目的的,指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象

只有当你希望创建一个可以包含任意内容的指令时,才使用transclude: true

controller(字符串String | 函数Function)

可选:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
* 字符串:以字符串的值为名字,查找注册在应用中的控制器的构造函数
* 函数:直接定义内联的控制器

可以向控制器中注入如下服务:

  • \$scope: 与指令元素相关联的当前作用域
  • \$element: 当前指令对应的元素
  • \$attrs: 由当前元素的属性组成的对象
  • \$transclude: 嵌入链接函数会与对应的嵌入作用域进行预绑定。transclude链接函数是实际被执行用来克隆元素和操作DOM的函数。controllerAs (字符串String)

用来设置控制器的别名,可以以此为名来发布控制器,并且作用域可以访问controllerAs。这样就可以在视图中引用控制器,甚至无需注入$scope。

require(字符串String | 数组Array)

字符串或数组元素的值是会在当前指令的作用域中使用的指令名称。require会将控制器注入到其值所指定的指令中,并作为当前指令的链接函数的第四个参数。

默认情况下,指令只会在自身的元素上查找控制器。可以用下面的前缀进行修饰,改变查找控制器时的行为:

  • ?: 如果在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数
  • ^: 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器
  • ?^: 将前面两个选项的行为组合起来,可选择地加载需要的指令并在父指令链中进行查找
  • 没有前缀: ,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误

compile(对象Object | 函数Function)

在compile函数内部,只对DOM进行操作,返回函数等效于使用link配置,返回对象的话包含两个函数:

  1. preLink会在编译阶段之后、指令连接到子元素之前运行
  2. postLink会在所有子元素指令都链接之后才运行

link(函数Function)

link函数会访问scope对象,其返回一个postLink函数。如果在compile中返回了post,那么link选项就会被忽略

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
link: function postLink(scope, iElement, iAttrs){}

compile和link

compile和link有许多异同:

compile函数只会被调用一次,而link函数的调用次数可能会很多。 compile用于对模板自身的转换,而link负责模型和视图之间进行动态关联 link函数能够访问scope作用域对象,而compile不会,因为在编译阶段,scope对象还不存在。 link和compile都会接收指令声明的DOM元素以及属性列表 compile可以返回preLink和postLink函数,而link只能返回postLink函数

AngularJS的生命周期

AngularJS应用启动后会进行编译和链接,作用域会同HTML进行绑定,应用可以对用户在HTML中进行的操作进行实时响应。

编译三个阶段
  1. 首先浏览器会用它的标准API将HTML解析成DOM。模板必须是可被解析的HTML。这是AngularJS和那些“以字符串为基础而非以DOM元素为基础的”模板系统的区别之处。
  2. DOM的编译是有\$compile方法来执行的。这个方法会遍历DOM并找到匹配的指令。一旦找到一个,它就会被加入一个指令列表中,这个列表是用来记录所有和当前DOM相关的指令的。 一旦所有的指令都被确定了,会按照优先级被排序,并且他们的compile方法会被调用。指令的\$compile()函数能修改DOM结构,并且要负责生成一个link函数(后面会提到)。\$compile方法最后返回一个合并起来的链接函数,这是链接函数是每一个指令的compile函数返回的链接函数的集合。
  3. 通过调用一步所说的链接函数来将模板与作用域链接起来。这会轮流调用每一个指令的链接函数,让每一个指令都能对DOM注册监听事件,和建立对作用域的的监听。这样最后就形成了作用域的DOM的动态绑定。任何一个作用域的改变都会在DOM上体现出来。 大致过程如下:

模板之中可能含有指令,指令之中可能又含有模板,模板之中又含有指令,由此形成一棵模板树。只有具有最高优先级的指令中的模板会被编译。如果一个元素已经有一个含有模板的指令了,永远不要对其用另一个指令进行修饰。一个指令会将内部子指令的模板合并在一起成为一个模板函数并返回,它无法查找父指令,只能通过模板函数访问内部子指令

ngModel

ngModel提供更底层的API来处理控制器内的数据。

为了设置作用域中的视图值,需要调用ngModel.\$setViewValue()函数,接受一个字符串参数value,表示想要赋予的实际值,然后: ngModel.\$setViewValue()方法会更新控制器本地的\$viewValue,然后将值传递给每一个\$parser函数 值被解析且\$parser所有函数都完成后,值会赋给\$modeValue属性,并且传递给指令中ng-model属性提供的表达式 所有步骤都完成后,\$viewChangeListeners中所有的监听器都会被调用

单独调用\$setViewValue()不会唤起一个新的digest循环,因此如果想更新指令,需要在设置\$viewValue后手动触发digest ngModel的\$render方法可以定义视图具体的渲染方式,它在$parser完成后被调用

ngModelController中有几个属性可用来检查甚至修改视图:

  1. \$viewValue: 保存着更新视图所需的实际字符串。
  2. \$modelValue:由数据模型持有。\$modelValue和\$viewValue可能是不同的,取决于\$parser流水线是否对其进行了操作。
  3. \$parsers:\$parsers的值是一个由函数组成的数组,其中的函数会以流水线的形式被逐一调用。ngModel从DOM中读取的值会被传入\$parsers中的函数,并依次被其中的解析器处理。
  4. \$formatters:\$formatters的值是一个由函数组成的数组,其中的函数会以流水线的形式在数据模型的值 发生变化时被逐一调用。它和\$parser流水线互不影响,用来对值进行格式化和转换,以便在绑定了这个值的控件中显示。
  5. \$viewChangeListeners:\$viewChangeListeners的值是一个由函数组成的数组,其中的函数会以流水线的形式在视图中的值发生变化时被逐一调用。通过\$viewChangeListeners,可以在无需使用\$watch的情况下实现类似的行为。由于返回值会被忽略,因此这些函数不需要返回值。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
angularJS学习之路(十七)---自定义指令
指令简单理解  就是   在元素上运行的函数    (这个函数有个名称,或者叫属性,比如id 等这种形式)
wust小吴
2019/07/08
7530
angularjs directive学习心得
transclude有三个选项,true, false, 和object.如果不显示指明的话,默认为false. 当为false的时候,则那个directive里面的指令不会嵌入到你写的模板里,举个例子 下面是html代码
嘿嘿嘿
2018/09/10
1.1K0
angularjs directive学习心得
angularjs 指令详解
一、指令定义 对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能。 首先来看个完整的参数示例再来详细的介绍各个参数的作用及用法: <div my-directive></div> 二、指令参数的作用和意义(这个地方只选常用的几种来讲一下) restrict[string] restrict是一个可选的参数。用于指定该指令在DOM中以何种形式被声明。默认值是A,即以属性的形式来进行声明。 可选值如下: E(元素) <my-directive></my-directive
柴小智
2018/04/10
2.3K0
angularjs 指令详解
Angular Directive 详解
如上所示,return的对象中会有很多的属性,这行属性都是用来定义directive的。
西南_张家辉
2021/02/02
2.8K0
4、Angular JS 学习笔记 – 创建自定义指令 [翻译中]
注意:本指南是针对已经熟悉AngularJS基础的开发者。如果您只是想要开始,建议您先去看教程。如果你在寻找指令的API,我们最近把他移动到$compile
前Thoughtworks-杨焱
2021/12/08
4.9K0
AngularJS入门心得4——漫谈指令scope
  上篇《AngularJS入门心得3——HTML的左右手指令》初步介绍了指令的概念和作用。已经和指令打过一个照面,就不会那么陌生了,今天主要介绍的是一个困扰了我很久终于想通的问题,这个问题与scope有关,可以看做是《AngularJS入门心得1——directive和controller如何通信》在scope上的补充和延伸。    小时候,老师就教会了我们盲人摸象这个成语,教导我们认识事物不能片面,缺少对于一个事物全局的认知。所以,说到指令,它的一个完整结构如下: angular.module('myA
JackieZheng
2018/01/16
2K0
AngularJS入门心得4——漫谈指令scope
2-进军 angular1.x 表达式和指令
使用驼峰法来命名一个指令, runoobDirective, 但在使用它时需要以 - 分割, runoob-directive:
西南_张家辉
2021/02/02
2.6K0
Angular源码分析之$compile
@(Angular) $compile,在Angular中即“编译”服务,它涉及到Angular应用的“编译”和“链接”两个阶段,根据从DOM树遍历Angular的根节点(ng-app)和已构造完毕的 $rootScope对象,依次解析根节点后代,根据多种条件查找指令,并完成每个指令相关的操作(如指令的作用域,控制器绑定以及transclude等),最终返回每个指令的链接函数,并将所有指令的链接函数合成为一个处理后的链接函数,返回给Angluar的bootstrap模块,最终启动整个应用程序。 ---- [
欲休
2018/03/15
1.6K0
再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结
ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}。
周陆军
2018/08/02
8.3K0
AngularJS 1 教程
随着浏览器性能提升,更多Web Page演变为Web App,特别是在中大型的项目中,就需要一个 前端框架 来:
小刀c
2022/08/16
4.8K0
达观数据对AngularJS技术的思考与实践
AngularJs诞生于2009年,最初由MiskoHevery和Adam Abrons开发,后来成为Google的项目。AngularJS 是一个为动态WEB应用设计的结构框架。它能让你使用HTML作为模板语言,通过扩展HTML的语法,让你能更清楚、简洁地构建你的应用组件。它的创新点在于,利用 数据绑定 和 依赖注入,它使你不用再写大量的代码了。这些全都是通过浏览器端的Javascript实现,这也使得它能够完美地和任何服务器端技术结合。(达观数据陈高星) 本文主要涵盖:AngularJsMVC模型、$s
达观数据
2018/03/30
5.7K0
带你走近AngularJS - 创建自定义指令
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------------------------------------------------------------------------------------------ 为什么使用AngularJS 指令? 使用过 AngularJS 的朋友应该最感兴趣的是它的指令。现今市场上的前端框架也只有AngularJS
葡萄城控件
2018/01/10
2.6K0
带你走近AngularJS - 创建自定义指令
AngularJS 指令的定义、语法、用法
AngularJS 是一个流行的前端框架,它提供了许多强大的功能和特性,其中之一就是指令(Directives)。指令是 AngularJS 中的核心概念之一,它允许开发者通过自定义 HTML 标签、属性或类名的方式来扩展 HTML 语义并增强页面的交互性和可重用性。本文将详细介绍 AngularJS 指令的定义、语法、用法以及一些实用技巧。
网络技术联盟站
2023/07/05
5380
AnagularJs之directive
  假如我们发现要写很多公共或是重用的dom、class、attr属性或是需要操作scope作用域,就要考虑代码最好不要copy、不要出现重复的代码段,好像是哪位大牛说的话,具体记不清了,反正就是为了性能优化等方面。
用户5640963
2019/07/26
1.2K0
带你走近AngularJS - 体验指令实例
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------------------------------------------------------------------------------------------ 之前我们已经介绍了所有的AngularJS 基础知识,下面让我们通过实例来加深记忆,体验自定义指令的乐趣。 手风琴指令 我们展示的第一个例子是手
葡萄城控件
2018/01/10
2.7K0
带你走近AngularJS - 体验指令实例
AngularJS浅谈-博客
AngularJS是啥?(一脸懵逼) 简介: AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款
双愚
2018/05/28
2.6K0
AngularJs之Scope作用域
  AngularJS 中,作用域是一个指向应用模型的对象,它是表达式的执行环境。作用域有层次结构,这个层次和相应的 DOM 几乎是一样的。作用域能监控表达式和传递事件。
用户5640963
2019/07/26
1.7K0
【Hybrid开发高级系列】AngularJS(二)——常用$服务
        scope是angularJS中的作用域(其实就是存储数据的地方),很类似javascript的原型链 。搜索的时候,优先找自己的scope,如果没有找到就沿着作用域链向上搜索,直至到达根作用域rootScope。
江中散人_Jun
2023/10/16
8220
【Hybrid开发高级系列】AngularJS(二)——常用$服务
AngularJS入门心得1——directive和controller如何通信
  粗略地翻了一遍《JavaScript DOM编程艺术》,就以为可以接过AngularJS的一招半式,一个星期过去了,我发现自己还是Too Young,Too Simple!(刚打照面的时候,我就被乱棍砸晕了-_-!)   1.AngularJS是何方神圣   Angular JS (Angular.JS) 是一组用来开发Web页面的框架、模板以及数据绑定和丰富UI组件。它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作。    AngularJS是为了克服HTML在构建应用上的不足而设计的
JackieZheng
2018/01/16
1.8K0
AngularJS入门心得1——directive和controller如何通信
【AngularJS】—— 10 指令的复用
前面练习了如何自定义指令,这里练习一下指令在不同的控制器中如何复用。   —— 来自《慕课网 指令3》   首先看一下一个小例子,通过自定义指令,捕获鼠标事件,并触发控制器中的方法。   单个控制器的标签指令   依然是先创建一个模块 var myAppModule = angular.module("myApp",[]);   在模块的基础上,创建控制器和指令 myAppModule.controller("myAppCtrl",["$scope",function($scop
用户1154259
2018/01/17
7660
【AngularJS】—— 10 指令的复用
相关推荐
angularJS学习之路(十七)---自定义指令
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验