AngularJS 自定义控件

AngularJS Custom Directives

好讨厌不带日期的博客,而且说得好啰嗦

自定义指令介绍

AngularJS 指令作用是在 AngulaJS 应用中操作 Html 渲染。比如说,内插指令 ( {{ }} ), ng-repeat 指令以及 ng-if 指令。

当然你也可以实现自己的。这就是 AngularJS 所谓的"教会 HTML 玩新姿势"。本文将告诉你如何做到。

指令类型

可以自定义的指令类型如下:

  • 元素
  • 属性
  • CSS class
  • Comment directives

这里面,AngularJS 强烈建议你用元素和属性类型,而不用 CSS class 和 comment directives (除非迫不得已)。

指令类型决定了指令何时被激活。当 AngularJS 在 HTML 模板中找到一个 HTML 元素的时候,元素指令被激活。当 AngularJS 找到一个 HTML 元素属性时,属性指令被激活。当 AngularJS 找到一个 CSS class 时, CSS class 指令被激活,最后,当 AngularJS 找到 HTML comment 时,comment directive 被激活。

基础例子

你可以向模块注册一个指令,像这样:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = "My first directive: {{textToInsert}}";return directive;
});

来看模块中调用的 directive() 函数。当你调用该函数时,意味着你要注册一个新指令。directive() 函数的第一个参数是新注册指令的名称。这是之后你在 HTML 模板中调用它的时候用的名称。例子中,我用了 'div' ,意思是说当 HTML 模板每次在找到 HTML 元素类型是 div 的时候,这个指令都会被激活。

传递给 directive 函数的第二个参数是一个工厂函数。调用该函数会返回一个指令的定义。 AngularJS 通过调用该函数来获取包含指令定义的 Javascript 对象。如果你有仔细看上面的例子,你会知道它返回的确是是一个 Javascript 对象。

这个从工厂函数中返回的 Javascript 对象有两个属性: restrict 和 template 字段。

restrict 字段用来设置指令何时被激活,是匹配到 HTML 元素时,还是匹配到元素属性时。也就是指令类型。把restrict 设置为 E 时,只有名为 div 的 HTML 元素才会激活该指令。把 restrict 设置为 A 时,只有名为 div 的 HTML 元素属性才会激活该指令。你也可以用 AE ,这样会使得匹配到元素名和元素属性名时,都可以激活该指令。

template 字段是一个 HTML 模板,用来替换匹配的 div 元素。它会把匹配到的 div 当成一个占位符,然后用 HTML 模板在同一位置来替换掉它。也就是说,HTML 模板替换匹配的到 HTML 元素。

比如说你的 HTML 页面有这样一段 HTML:

<!-- lang: js -->
<div ng-controller="MyController" ><div>This div will be replaced</div>
</div>

当 AngularJS 找到内嵌的 div 的时候,会激活自定义的指令。然后把该 div 元素替换掉,替换后的 HTML 将变成这样:

<!-- lang: js -->
My first directive: {{textToInsert}}

然后你看到了,这段 HTML 里面包含了一个内插指令 ({{textToInsert}})。AngularJS 会再执行一次,让内插指令实际值显示出来。然后 $scope.textToInsert 属性将会在这个 HTML 点上替换掉内插指令占位符。

template 和 templateUrl 属性

创建自定义指令最简单的例子就是上面这样了。你的指令用来生成 HTML,然后你把 HTML 放到指令定义对象的 template 属性中。下面这个例子是上面那最简单的例子的重复,注意 template 部分:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = "My first directive: {{textToInsert}}";return directive;
});

如果 HTML 模板越来越大,把它写在一个 Javascript 字符串中肯定非常难维护。你可以把它放到一个单独的文件中,然后 AngularJS 可以通过这个文件把它加载进来。然后再把 HTML 模板文件的 URL 放到指令定义对象的 templateUrl 属性中。下面是例子:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = "/myapp/html-templates/div-template.html";return directive;
});

然后 AngularJS 会从 templateUrl 属性中设置的 URL 将 HTML 模板加载进来。

用独立的 HTML 模板文件,设置 templateUrl 属性,在你要创建更多的通用指令时会显得更加有用,比如说用来显示用户信息的指令。例子:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = "/myapp/html-templates/userinfo-template.html";return directive;
});

例子创建了一个指令,当AngularJS 找到一个 元素的时候就会激活它。AngularJS 加载指向 /myapp/html-templates/userinfo-template.html 的模板并解析它,它就像从一开始就被嵌在上一级 HTML 文件中一样。

从指令中隔离 $scope

在上面的例子中,把 userinfo 指令硬绑定到了 $scope ,因为 HTML 模板是直接引用 textToInsert 属性的。直接引用 $scope 让指令在同一个 controller 中的时候,非常难复用,因为 $scope 在同一个 controller 中的值都是一样的。比如说,你在页面的 HTML 中这样写的时候:

<!-- lang: js -->
<userinfo></userinfo>
<userinfo></userinfo>

这两个 元素会被同样的 HTML 模板取代,然后绑定到同样的 $scope 变量上。结果就是两个 元素将会被一模一样的 HTML 代码给替换了。

为了把两个 元素绑定到 $scope 中的不同的值,你需要给 HTML 模板一个 isolate scope。

所谓 isolate scope 是绑定在指令上的独立的 scope 对象。下面是定义的例子:

<!-- lang: js -->
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E';directive.template = "User : {{user.firstName}} {{user.lastName}}";directive.scope = {user : "=user"}return directive;
})

请看 HTMl 模板中的两个内插指令 {{user.firstName}} 和 {{user.lastName}}。注意 user. 部分。以及directive.scope 属性。 directive.scope 是个带 user 属性的 Javascript 对象。于是 directive.scope 就成为了 isolate scope 对象,现在 HTML 模板被绑到了 directive.scope.user 上(通过 {{user.firstName}} 和 {{user.lastName}} 内插指令)。

directive.scope.user 被设置为 "=user" 。意思是说 directive.scope.user 和 scope 中的属性绑在一起的(不是 isolate scope),scope 中的属性通过 user 属性传入 元素。听起来挺费劲的,直接看例子:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo>

这两个 元素都有 user 属性。user 的值指向了 $scope 中同名属性,被指定的 $scope 中的属性将在 userinfo 的 isolate scope object 中被使用。

下面是完整的例子:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo><script>
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E';directive.template = "User : <b>{{user.firstName}}</b> <b>{{user.lastName}}</b>";directive.scope = {user : "=user"}return directive;
});myapp.controller("MyController", function($scope, $http) {$scope.jakob = {};$scope.jakob.firstName = "Jakob";$scope.jakob.lastName  = "Jenkov";$scope.john = {};$scope.john.firstName = "John";$scope.john.lastName  = "Doe";
});</script>

compile() 和 link() 函数

如果你需要在你的指令中做更高级的操作,单纯使用 HTML 模板做不到的时候,你可以考虑使用 compile() 和 link() 函数。

compile() 和 link() 函数定义了指令如何修改匹配到的 HTML。

当指令第一次被 AngularJS 编译的时候 (在 HTML 中第一次被发现),compile() 函数被调用。compile() 函数将为该元素做一次性配置。

然后 compile() 函数以返回 link() 作为终结。link() 函数将在每次元素被绑到 $scope 数据时,都被调用。

下面是例子:

<!-- lang: js -->
<script>
myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.compile = function(element, attributes) {// do one-time configuration of element.var linkFunction = function($scope, element, atttributes) {// bind element to data in $scope}return linkFunction;}return direc
t```  
ive;
});    
</script>    
**compile() 函数带两个参数: element 和 attributes。**element 参数是 jqLite 包装过的 DOM 元素。AngularJS 有一个简化版 jQuery 可以用于操作 DOM,所以对 element 的 DOM 操作方式和你在 jQuery 中所知的一样。attributes 参数是包含了 DOM 元素中的所有的属性集合的 Javascript 对象。因此,你要访问某个属性你可以这样写 attributes.type。link() 函数带三个参数: $scope,element 和 attributes。element 和attributes 参数和传到 compile() 函数中的一样。$scope 参数是正常的 scope 对象,或者当你在指令定义对象中定义了 isolate scope 的时候,它就是 isolate scope。compile() 和 link() 的命名相当混乱。它们肯定是受编译队伍的启发而命名的。我可以看到相似点,不过一个编译器是传入一次,然后输出。而指令则是配置一次 HTML 元素,然后在之后的 $scope 对象改变时进行更新。compile() 函数如果叫做 create(), init() 或者 configure()也许会更好。这样可以表达出这个函数只会被调用一次的意思。而 link() 函数如果叫 bind() 或者 render() 也许会更好,能更好的表达出这样的意思,在指令绑定数据或者重绑定数据的时候,这个函数将会被调用。下面是一个完整的例子,演示了指令使用 compile() 和 link() 函数的:


<userinfo >This will be replaced</userinfo>

myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.compile = function(element, attributes) {element.css("border", "1px solid #cccccc");var linkFunction = function($scope, element, attributes) {element.html("This is the new content: " + $scope.firstName);element.css("background-color", "#ffff00");}return linkFunction;}return directive;
})
myapp.controller("MyController", function($scope, $http) {$scope.cssClass = "notificationDiv";$scope.firstName = "Jakob";$scope.doClick = function() {console.log("doClick() called");}
});


compile() 函数设置 HTML 元素的 border 。它只执行一次,因为 compile() 函数只执行一次。**link() 替换 HTML 元素内容,并且把背景颜色设置为黄色。**把设置 border 放在 compile(), 把背景颜色放在 link() 没啥特别的理由。你可以把所有的操作都丢到 compile(),或者都放到 link()。如果都放到 compile() 它们只会被设置一次(你需要它们是常量的话)。如果放到了 link(),它们会在每次 HTML 元素被绑到 $scope 的时候都发生变化。当你希望根据 $scope 中的数据来设置 boarder 和背景颜色的时候这非常有用。**只设置 link() 函数**有时候你的指令可能不需要 compile() 。你只需要用到 link()。这种情况下,你可以直接设置指令定义对象中的 link() 函数。下面是一个对上面例子的修改,只用 link 函数:


<userinfo >This will be replaced</userinfo>

myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.link = function($scope, element, attributes) {element.html("This is the new content: " + $scope.firstName);element.css("background-color", "#ffff00");}return directive;
})
myapp.controller("MyController", function($scope, $http) {$scope.cssClass = "notificationDiv";$scope.firstName = "Jakob";$scope.doClick = function() {console.log("doClick() called");}
});

注意 link() 方法和之前例子中返回的 link() 是完全一样的。**通过 Transclusion 封装元素的指令**到目前为止,我们看到的所有例子,都是把匹配到的元素内容给替换为指令的指定内容,不管是通过 Javascript 也好或者 HTML 模板也好。不过如果遇到内容中有部分是开发者可以指定的内容的时候呢?比如说:


This is a transcluded directive {{firstName}}

标记为 <mytransclude> 的元素,它的部分内容可以由开发者设置。因此,这部分 HTML 不应该被指令的 HTML 模板给替换。我们实际上是希望这部分 HTML 由 AngularJS 来处理的。这个处理叫做 "transclusion"。 1为了能让 AngularJS 把这部分 HTML 放到指令内部处理,你必须设置指令定义对象的 transclude 属性为 true。你还需要告诉 AngularJS,指令的 HTML 模板中哪一部分需要把 transcluded HTML 包含进来。你可以通过插入 ng-transclude 属性 (实际上,是一个指令) 到 HTML 模板的 HTML 元素中,标记你想要添加 transcluded HTML 的元素。下面是一个 AngularJS 指令,演示如何使用 transclusion:


This is a transcluded directive {{firstName}}

myapp = angular.module("myapp", []);
myapp.directive('mytransclude', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.transclude = true;directive.template = "<div class='myTransclude' ng-transclude></div>";return directive;
});
myapp.controller("MyController", function($scope, $http) {$scope.firstName = "Jakob";
});

注意 <mytransclude> 元素内的 HTML。这部分 HTML 代码包含了内插指令 {{firstName}}。我们希望 AngularJS 来为我们处理这部分 HTML,让内插指令执行。为了实现这个目的,我在指令定义对象中把 transclude 设置为 true。我还在 HTML 模板中用到了 ng-transclude 属性。这个属性告诉 AngularJS 什么元素需要插入到 transcluded HTML。1: 说实话,我没看懂那个定义,说的太TM难懂了,而且我好不爽写代码没输出的教程。只好自己动手做做例子。我觉得其实应该是这样的,把目标元素内容作为一个整体,拿到 HTML 模板中来,添加到 ng-transclude 指定的标签下。这个处理,我觉得应该就是叫做 transcluded。比如说刚才的例子(有些 bug,自己修正一下),因为 directive.transclude = true; ,所以原来 <mytransclude> 元素内的 HTML:


This is a transcluded directive {{firstName}}

在激活指令 'mytransclude' 的时候,会被拿到 'mytransclude' 指令的模板中来,放到被 ng-transclude 指定的


"

"
中。于是最终输出的结果应该是:


<div class='myTransclude' ng-transclude><span class="ng-scope ng-binding">This is a transcluded directive Jakob</span>
</div>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle 监听加密 tcps,通过oracle wallet配置listener tcps加密

一 配置客户端和服务端的wallet2端配置方法一致&#xff0c;相互添加证书orapki wallet create -wallet "/u01/oracle/wallet" -pwd Wdkf984jkkgekj434FKFD -auto_login_localorapki wallet add -wallet "/u01/oracle/wallet" -pwd Wdkf984jkkgekj434FKFD …

[财务知识] debt debit credit 的区别于联系

https://blog.csdn.net/sjpljr/article/details/70169303 剑桥词典解释分别为&#xff1a; Debt [C or U ] n.something, especially money, which is owed to someone else, or the state of owing something借款&#xff0c;欠款&#xff1b;债务He ran/got into debt ( borr…

SpringMVC视图解析器

SpringMVC视图解析器 前言 在前一篇博客中讲了SpringMVC的Controller控制器&#xff0c;在这篇博客中将接着介绍一下SpringMVC视 图解析器。当我们对SpringMVC控制的资源发起请求时&#xff0c;这些请求都会被SpringMVC的DispatcherServlet处理&#xff0c;接着 Spring会分析看…

TIOBE 10月编程语言排行榜 : GO 问鼎本年度语言 ?

距离2016年度编程语言的公布只剩3个月了&#xff0c;谁将夺得桂冠&#xff1f; 与去年同期相比&#xff0c;2016年只有Go语言和Groovy语言的增长率超过了1%。 需要注意的是&#xff0c;Groovy语言2015年以一个爆炸性增长的收尾&#xff0c;所以到2017年1月左右的增长速度可能不…

校友邮箱_freeCodeCamp校友网络:FCC校友的自主指导网络

校友邮箱by peterWeinberg彼得温伯格 freeCodeCamp校友网络&#xff1a;FCC校友的自主指导网络 (The freeCodeCamp Alumni Network: A homegrown mentorship network for FCC alumni) For the last year, I’ve been spending nearly all my free time learning to code. I’v…

oracle severity,ORACLE10G如何清除OEM下的历史警告信息

ORACLE10G如何清除OEM下的历史警告信息问题描述&#xff1a;OEM的HOME页面可以显示ORACLE的报警信息&#xff0c;但报警事件清除后该信息不会自动清除。随着时间的增长&#xff0c;信息量逐渐加大&#xff0c;解决方法是手工予以清除。SampleCluster DatabaseTablespaces FullT…

使用 ReSharper,输入即遵循 StyleCop 的代码格式化规范

StyleCop 可以帮助强制执行代码格式化规范&#xff0c;ReSharper 可以帮助你更高效地编写代码。把两者结合起来&#xff0c;你便能高效地编写符合团队强制格式化规范的代码来。 本文就介绍如何使用 ReSharper 来高效地遵循 StyleCop 的代码格式化规范。 本文内容 安装插件 Styl…

Oracle数据库备份恢复,巡检须要关注的对象设置以及相关恢复概述

数据库备份恢复。巡检须要关注的对象设置&#xff1a; 1.数据库名称&#xff0c;以及DBID&#xff1b; --dbid在v$database中 SYSORCL>select dbid,name from v$database; DBID NAME ---------- --------- 1385095721 ORCL 2.控制文件的位置&#xff1b; s…

Python迭代器

一、文件迭代器 readline&#xff08;&#xff09;每次读取文件的一行&#xff0c;每次调用readline方法会自动到下一行&#xff0c;到文件末尾时&#xff0c;会返回空字符串。 _next_()方法同readline&#xff08;&#xff09;一样&#xff0c;只是到最后一行会引发stopiterat…

成千上万的在线课程时,如何保持理智和学习编码

by Travis Chan通过特拉维斯陈 成千上万的在线课程时&#xff0c;如何保持理智和学习编码 (How to stay sane and learn to code when there are thousands of online courses) We live in the information age. Information about anything we can think of is accessible to…

oracle中noguarantee,聊聊UNDO_RETENTION作用(修改guarantee)

oracle10g中&#xff0c;针对dba_tablespace&#xff0c;加了其中一个额外列是retention.回忆一下Oracle 10g之前,在自动Undo管理的模式下&#xff0c;我们都知道undo_retention参数的作用是用来控制当transaction被commit之后&#xff0c;undo信息的保留时间。这些undo信息可以…

【Hankson 的趣味题】

可能我只适合这道题的50分 但还是要争取一下的 我们知道对于\(gcd\)和\(lcm\)有这样的定义 \(a\prod _{i1}^{\pi(a)}p_i^{d_{i}}\) \(b\prod _{i1}^{\pi(b)}p_i^{g_{i}}\) 那么则有 \(gcd(a,b)\prod_{i1}^{\pi(max(a,b))} p_i^{min(g_i,d_i)}\) \(lcm(a,b)\prod_{i1}^{\pi(max(…

C# 控件双缓冲控制 ControlStyles 枚举详解

ControlStyles 枚举.NET Framework 4指定控件的样式和行为。 此枚举有一个 FlagsAttribute 特性&#xff0c;通过该特性可使其成员值按位组合。 命名空间&#xff1a; System.Windows.Forms程序集&#xff1a; System.Windows.Forms&#xff08;在 System.Windows.Forms.dll …

协作机器人 ai算法_如果我们希望人工智能为我们服务而不是不利于我们,我们需要协作设计...

协作机器人 ai算法by Mariya Yao姚iya(Mariya Yao) 如果我们希望人工智能为我们服务而不是不利于我们&#xff0c;我们需要协作设计 (If we want AI to work for us — not against us — we need collaborative design) The trope “there’s an app for that” is becoming …

Shadow Brokers 公布 2.1 万美元的 0day 订阅服务

神秘黑客组织 Shadow Brokers 宣布将向支付 2.1 万美元 0day 订阅服务的个人公布最新一批的 NSA 工具&#xff0c;这一声明给全世界的白帽子黑客或安全研究人员造成了一场伦理危机。 一方面&#xff0c;Shadow Brokers 此前释出过创造出勒索软件 WannaCry 的 NSA 工具&#xff…

linux awk 常见字符串处理

awk指定输出列&#xff1a; awk {print $0} file #打印所有列awk {print $1} file #打印第一列 awk {print $1, $3} file #打印第一和第三列 cat file | awk {print $3, $1} #打印第三列和第一列&#xff0c;注意先后顺序。 cat file | awk {print $3, $NF} #打印第三列…

oracle ldap 配置,ldap 安装

一、安装步骤1:配置yum源挂着盘镜像时用到&#xff1a; 这里不做解释;(yum clean all && yum makecache)2:安装OpenLDAP组件1)安装OpenLDAP组件命令如下:[rootgitea ~]# yum install openldap openldap-servers openldap-clients openldap-devel compat-openldap -ycom…

scp跨主机拷贝工具

参考&#xff1a;http://www.cnblogs.com/hitwtx/archive/2011/11/16/2251254.html SSH上A机&#xff0c;要将10.1.17.95机/tpdata/shell_script/下面的crontab.tar.gz文件拷贝到A机的当前文件夹下面&#xff1a; scp weblogic10.1.17.95:/tpdata/shell_script/crontab.tar.gz …

Google Chrome浏览器可能在您不知情的情况下破坏了您的测试

by Robert Axelsen罗伯特阿克森(Robert Axelsen) Google Chrome浏览器可能在您不知情的情况下破坏了您的测试 (Google Chrome might have broken your tests without you even knowing about it) My colleague just discovered that Chrome 58 (released April 19th) has sile…

Java 9 将采用新的版本字符串格式

在现有的版本编码格式使用了两年之后&#xff0c;从Java 9开始&#xff0c;Java版本方案将根据业内软件版本编码的最佳实践进行修改。使用或解析Java版本字符串的应用程序开发人员要注意了&#xff0c;因为这种变化可以会影响他们的应用程序。 正如JEP 223所阐述的那样&#xf…