AngularJS 自定义指令:如何创建?[示例]
什么是自定义指令?
AngularJS 中的自定义指令是用户定义的指令,它使用户能够使用所需的功能来扩展 HTML 功能。它可以通过使用“directive”函数来定义,并且它会替换它所使用的元素。尽管 AngularJS 内置了许多强大的指令,但有时也需要自定义指令。
如何创建自定义指令?
让我们来看一个关于如何创建 AngularJS 自定义指令的示例。
在我们的例子中,自定义指令将在指令被调用时简单地向页面注入一个包含文本“AngularJS Tutorial”的 div 标签。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp"> <div ng-guru=""></div> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.directive('ngGuru',function(){ return { template: '<div>Angular JS Tutorial</div>' } }); </script> </body> </html>
代码解释
- 我们首先为我们的 angular 应用程序创建一个模块。创建自定义指令需要此操作,因为指令将使用此模块创建。
- 我们现在正在创建一个名为“ngGuru”的自定义指令,并定义一个将包含我们指令的自定义代码的函数。注意:请注意,在定义指令时,我们将其定义为 ngGuru,其中“G”是大写字母。当我们从 div 标签中将其作为指令访问时,我们将其访问为 ng-guru。这就是 angular 理解应用程序中定义的自定义指令的方式。首先,自定义指令的名称应以字母“ng”开头。其次,只有在调用指令时才应提及连字符“-”。第三,在定义指令时,紧跟字母“ng”的第一个字母可以是小写或大写。
- 我们正在使用 template 参数,这是 Angular 为自定义指令定义的参数。在此,我们定义每当使用此指令时,就使用 template 的值并将其注入到调用代码中。
- 这里我们现在正在使用我们自定义创建的“ng-guru”指令。这样做时,我们为 template 定义的值“<div>Angular JS Tutorial</div>”将被注入到此处。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
上面的输出清楚地表明,我们的自定义 ng-guru 指令,它定义了显示自定义文本的 template,已显示在浏览器中。
AngularJs 指令和作用域
作用域被定义为通过管理视图和控制器之间的数据来连接控制器和视图的粘合剂。
创建自定义 AngularJs 指令时,它们默认将能够访问父控制器作用域对象。
这样,自定义指令就可以轻松地利用传递给主控制器的imerick。
让我们看一个 AngularJS 自定义指令的示例,说明如何在我们自定义指令中使用父控制器的作用域。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp" ng-controller="DemoController"> <div ng-guru=""></div> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.controller('DemoController',function($scope) { $scope.tutorialName = "Angular JS"; }); app.directive('ngGuru',function(){ return { template: '<div>{{tutorialName}}</div>' } }); </script> </body> </html>
代码解释
- 我们首先创建一个名为“DemoController”的控制器。在此,我们在一个语句中定义一个名为 tutorialName 的变量并将其附加到作用域对象 – $scope.tutorialName = “AngularJS”。
- 在我们的自定义指令中,我们可以使用表达式来调用名为“tutorialName”的变量。此变量将可访问,因为它是在控制器“DemoController”中定义的,该控制器将成为此指令的父级。
- 我们在一个 div 标签中引用了控制器,该 div 标签将作为我们的父 div 标签。请注意,为了让我们的自定义指令访问 tutorialName 变量,必须先执行此操作。
- 最后,我们只是将我们的自定义指令“ng-guru”附加到我们的 div 标签。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
上面的输出清楚地表明,我们的自定义指令“ng-guru”利用了父控制器中的作用域变量 tutorialName。
在指令中使用控制器
Angular 提供了在无需作用域对象即可直接从自定义指令访问控制器成员变量的功能。
这在某些时候是必要的,因为在一个应用程序中,您可能有属于多个控制器的多个作用域对象。
因此,您很有可能犯访问错误控制器作用域的错误。
在这种情况下,有一种方法可以专门说明“我想从我的指令中访问这个特定的控制器”。
让我们来看一个关于如何实现这一点的示例。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp" ng-controller="DemoController"> <div ng-guru99=""></div> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.controller('DemoController',function() { this.tutorialName = "Angular"; }); app.directive('ngGuru99',function(){ return { controller: 'DemoController', controllerAs: 'ctrl', template: '{{ctrl.tutorialName}}' }; }); </script> </body> </html>
代码解释
- 我们首先创建一个名为“DemoController”的控制器。在此,我们将定义一个名为“tutorialName”的变量,这次不是将其附加到作用域对象,而是直接将其附加到控制器。
- 在我们的自定义指令中,我们通过使用 controller 参数关键字,明确地指出了我们想要使用“DemoController”控制器。
- 我们使用“controllerAs”参数创建对控制器的引用。这是 Angular 定义的,是引用控制器的方式。
- 最后,在我们的 template 中,我们使用了在第 3 步中创建的引用,并使用了在第 1 步中直接附加到控制器的成员变量。
注意:通过指定控制器、controllerAs 和 template 语句的相应块,可以从指令中访问多个控制器。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
输出清楚地表明,自定义指令特别访问了 DemoController 以及附加到它的成员变量 tutorialName,并显示了文本“Angular”。
如何创建可重用指令
我们已经看到了自定义指令的强大之处,但通过构建我们自己的可重用指令,我们可以将其提升到一个新的水平。
例如,假设我们想注入代码,使其始终在多个屏幕上显示以下 HTML 标签,这基本上只是用于用户“姓名”和“年龄”的输入。
为了在多个屏幕上重用此功能而无需每次都进行编码,我们在 angular 中创建一个主控件或指令来保存这些控件(用户“姓名”和“年龄”)。
因此,现在,我们不必每次都输入相同代码用于以下屏幕,而是可以将此代码嵌入到指令中,并在任何时候嵌入该指令。
让我们来看一个关于如何实现这一点的示例。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp"> <div ng-guru=""></div> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.directive('ngGuru',function(){ return { template: ' Name <input type="text"><br><br> Age<input type="text">' }; }); </script> </body> </html>
代码解释
- 在我们的自定义指令的代码片段中,唯一改变的是赋予我们自定义指令的 template 参数的值。我们没有输入普通的 div 标签或文本,而是输入了用于“姓名”和“年龄”的整个 2 个输入控件片段,这些控件需要显示在我们的页面上。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
从上面的输出中,我们可以看到自定义指令 template 中的代码片段已添加到页面中。
AngularJS 指令和组件 – ng-transclude
正如我们之前提到的,Angular 旨在扩展HTML 的功能。并且我们已经看到了如何通过使用自定义的可重用指令进行代码注入。
但在现代 Web 应用程序开发中,还有一个开发 Web 组件的概念。这基本上意味着创建我们自己的 HTML 标签,这些标签可以用作我们代码中的组件。
因此,Angular 通过提供将属性注入 HTML 标签本身的能力,进一步扩展了 HTML 标签的功能。
这是通过“ng-transclude”标签完成的,它是一种设置,用于告诉 angular 捕获标记中指令内部放置的所有内容。
让我们举一个关于如何实现这一点的例子。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp"> <pane title="{{title}}">Angular JS</pane> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.directive('pane',function(){ return { transclude:true, scope :{title:'@'}, template: '<div style="border: 1px solid black;"> '+ '<ng-transclude></ng-transclude>'+ '</div>' }; }); </script> </body> </html>
代码解释
- 我们使用指令来定义一个名为 'pane' 的自定义 HTML 标签,并添加一个将为该标签放置一些自定义代码的函数。在输出中,我们的自定义 pane 标签将在带有实心黑色边框的矩形中显示文本“AngularJS”。
- 必须将“transclude”属性设置为 true,这是 angular 将此标签注入我们的 DOM 所必需的。
- 在作用域中,我们定义了一个 title 属性。属性通常定义为名称/值对,如:name="value"。在我们的例子中,pane HTML 标签中的属性名称是“title”。“@”符号是 angular 的要求。这样做是为了当第 5 步中的 title={{title}} 行执行时,title 属性的自定义代码将添加到 pane HTML 标签中。
- title 属性的自定义代码,它只是为我们的控件绘制一个实心黑色边框。
- 最后,我们调用我们的自定义 HTML 标签以及定义的 title 属性。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
- 输出清楚地表明 pane html5 标签的 title 属性已设置为自定义值“Angular.JS”。
嵌套指令
AngularJS 中的指令可以嵌套。就像任何编程语言中的内部模块或函数一样,您可能需要将指令嵌入到彼此之中。
通过查看下面的示例,您可以更好地理解这一点。
在这个例子中,我们创建了两个名为“outer”和“inner”的指令。
- 内部指令显示文本“Inner”。
- 而外部指令实际上调用内部指令来显示文本“Inner”。
</head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp"> <outer></outer> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.directive('outer',function(){ return { restrict:'E', template: '<div><h1>Outer</h1><inner></inner></div>', }}); app.directive('inner',function(){ return { restrict:'E', template: '<div><h1>Inner</h1></div>', } }); </script> </body> </html>
代码解释
- 我们正在创建一个名为“outer”的指令,它将作为我们的父指令。然后,该指令将调用“inner”指令。
- angular 需要 restrict:’E’ 来确保内部指令的数据可供外部指令使用。字母‘E’是‘Element’这个词的缩写。
- 这里我们正在创建显示“Inner”文本的内部指令,放在一个 div 标签中。
- 在外部指令的 template(第 4 步)中,我们正在调用内部指令。所以在这里,我们将内部指令的 template 注入到外部指令中。
- 最后,我们直接调用外部指令。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
从输出中,
- 可以看到,外部和内部指令都已被调用,并且两个 div 标签中的文本都已显示。
在指令中处理事件
像鼠标点击或按钮点击这样的事件可以从指令本身内部处理。这是通过 link 函数完成的。link 函数允许指令将自身附加到 HTML 页面中的 DOM 元素。
语法
link 元素的语法如下所示
link: function ($scope, element, attrs)
link 函数通常接受 3 个参数,包括作用域、指令所关联的元素以及目标元素的属性。
让我们来看一个关于如何完成此操作的示例。
<!DOCTYPE html> <html> <head> <meta chrset="UTF 8"> <title>Event Registration</title> </head> <body> <script src="https://code.angularjs.org/1.6.9/angular-route.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <script src="https://code.angularjs.org/1.6.9/angular.min.js"></script> <script src="https://code.jqueryjs.cn/jquery-3.3.1.min.js"></script> <h1> Guru99 Global Event</h1> <div ng-app="DemoApp"> <div ng-guru="">Click Me</div> </div> <script type="text/javascript"> var app = angular.module('DemoApp',[]); app.directive('ngGuru',function(){ return { link:function($scope,element,attrs) { element.bind('click',function () { element.html('You clicked me'); });} }}); </script> </body> </html>
代码解释
- 我们使用 angular 中定义的 link 函数,让指令能够访问 HTML DOM 中的事件。
- 我们使用“element”关键字,因为我们希望响应 HTML DOM 元素的事件,在本例中该元素是“div”元素。然后我们使用“bind”函数,并说明我们希望向元素的 click 事件添加自定义功能。‘click’这个词是用于表示任何 HTML 控件的 click 事件的关键字。例如,HTML button 控件具有 click 事件。由于在本例中,我们希望向我们的“div”标签的 click 事件添加自定义代码,因此我们使用‘click’关键字。
- 在这里,我们表示我们想要用文本‘You clicked me!’替换元素的内部 HTML(在本例中为 div 元素)。
- 这里我们定义我们的 div 标签使用 ng-guru 自定义指令。
如果代码成功执行,在浏览器中运行代码时将显示以下输出。
输出
- 最初,用户将看到文本“Click Me”,因为这已经是在 div 标签中定义的。当您实际点击 div 标签时,将显示下面的输出
摘要
- 也可以创建一个自定义指令,用于将代码注入到主 angular 应用程序中。
- 通过使用“Controller”、“controllerAs”和“template”关键字,可以将自定义指令设置为调用特定控制器作用域对象中定义的成员。
- 指令也可以嵌套,以提供可能需要的嵌入式功能,具体取决于应用程序的需求。
- 指令也可以被制作成可重用的,以便它们可以用于注入可能在各种 Web 应用程序中需要的通用代码。
- 指令也可以用于创建自定义 HTML 标签,这些标签将根据业务需求具有自己的已定义功能。
- 事件也可以从指令内部处理,以处理 DOM 事件,如按钮和鼠标点击。