Home > Web Front-end > JS Tutorial > body text

Practical Development Guide for Directives in AngularJS (1)_AngularJS

WBOY
Release: 2016-05-16 15:09:54
Original
1480 people have browsed it

Directives are the most important part of any AngularJS application. Although AngularJS already provides a very rich set of directives, it is often necessary to create application-specific directives. This tutorial will tell you how to customize instructions and introduce how to use them in actual projects. At the end of this article (Part 2), I will guide you on how to use Angular directives to create a simple notepad application.

Overview

A directive used to introduce new HTML syntax. Directives are tags on DOM elements that cause the element to have a specific behavior. For example, static HTML doesn't know how to create and display a date picker control. To make HTML recognize this syntax, we need to use directives. The directive creates an element that supports date selection in some way. We'll walk through how this is done step by step. If you've ever written an AngularJS application, you've definitely used directives, whether you realized it or not. You must have used simple commands such as ng-mode, ng-repeat, ng-show, etc. These directives give specific behaviors to DOM elements. For example, ng-repeat repeats a specific element, and ng-show conditionally displays an element. If you want an element to support dragging, you also need to create a directive to implement it. The basic idea behind the directive is simple. It makes HTML truly interactive by binding event listeners to elements or changing the DOM.

jQuery perspective

Imagine how to create a date picker using jQuery. First, we add a normal input box to the HTML, and then use jQuery to call $(element).dataPicker() to convert it into a date picker. But, think about it. When a designer comes and examines the HTML markup, can he/she immediately guess what this field actually represents? Is this just a simple input box, or a date picker? You'll need to look at the jQuery code to determine these. Angular's approach is to use a directive to extend HTML. So, a date picker directive can be of the following form:

<input type="text" />

Copy after login

Or this:

<input type="text" />
Copy after login

This way of creating UI components is more direct and clear. You can easily figure out what this is by looking at the elements.

Create a custom directive:

An Angular directive can have the following four forms of expression: 1. A new HTML element () 2. Attributes of the element (

var app = angular.module('myapp', []);
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
Copy after login

In the above code, the app.directive() method registers a new directive in the module. The first parameter of this method is the name of the directive. The second parameter is a function that returns the directive definition object. If your directive depends on other objects or services, such as $rootScope, $http, or $compile, they can be injected at this time. This directive is used as an element in HTML, as follows:

<hello-world/>
//OR
<hello:world/>
Copy after login

Or, use it as an attribute:

<div hello-world></div>
//OR
<div hello:world/>
Copy after login

If you want to comply with HTML5 specifications, you can add x- or data- prefix in front of the element. So the following tag will also match the helloWorld directive:

<div data-hello-world></div>
//OR
<div x-hello-world></div>
Copy after login

注意: 在匹配指令的时候,Angular会在元素或者属性的名字中剔除 x- 或者 data- 前缀。 然后将 – 或者 : 连接的字符串转换成驼峰(camelCase)表现形式,然后再与注册过的指令进行匹配。这是为什么,我们在HTML中以 hello-world 的方式使用 helloWorld 指令。其实,这跟HTML对标签和属性不区分大小写有关。 尽管上面的指令仅仅实现了静态文字的显示,但是这里还是有一些有趣的点值得我们去挖掘。我们在指令定义过程中使用了三个属性来配置指令。我们来一一介绍他们的作用。

restrict – 这个属性用来指定指令在HTML中如何使用(还记得之前说的,指令的四种表示方式吗)。在上面的例子中,我们使用了 ‘AE'。所以这个指令可以被当作新的HTML元素或者属性来使用。如果要允许指令被当作class来使用,我们将 restrict 设置成 ‘AEC'。

template – 这个属性规定了指令被Angular编译和链接(link)后生成的HTML标记。这个属性值不一定要是简单的字符串。template 可以非常复杂,而且经常包含其他的指令,以及表达式({{ }})等。更多的情况下你可能会见到 templateUrl, 而不是 template。所以,理想情况下,你应该将模板放到一个特定的HTML文件中,然后将 templateUrl 属性指向它。
replace – 这个属性指明生成的HTML内容是否会替换掉定义此指令的HTML元素。在我们的例子中,我们用 的方式使用我们的指令,并且将 replace 设置成 true。所以,在指令被编译之后,生成的模板内容替换掉了 。最终的输出是

Hello World!!

。如果你将 replace 设置成 false,也就是默认值,那么生成的模板会被插入到定义指令的元素中。
打开这个 plunker,在”Hello World!!”右键检查元素内容,来更形象地明白这些。

Link函数和Scope

指令生成出的模板其实没有太多意义,除非它在特定的scope下编译。默认情况下,指令并不会创建新的子scope。更多的,它使用父scope。也就是说,如果指令存在于一个controller下,它就会使用这个controller的scope。 如何运用scope,我们要用到一个叫做 link 的函数。它由指令定义对象中的link属性配置。让我们来改变一下我们的 helloWorld 指令,当用户在一个输入框中输入一种颜色的名称时,Hello World 文字的背景色自动发生变化。同时,当用户在 Hello World 文字上点击时,背景色变回白色。 相应的HTML标记如下:

<body ng-controller="MainCtrl">
<input type="text" ng-model="color" placeholder="Enter a color" />
<hello-world/>
</body>
Copy after login

修改后的 helloWorld 指令如下:

app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
elem.css('background-color', 'white');
scope.$apply(function() {
scope.color = "white";
});
});
elem.bind('mouseover', function() {
elem.css('cursor', 'pointer');
});
}
};
});
Copy after login

我们注意到指令定义中的 link 函数。 它有三个参数:

scope – 指令的scope。在我们的例子中,指令的scope就是父controller的scope。
elem – 指令的jQLite(jQuery的子集)包装DOM元素。如果你在引入AngularJS之前引入了jQuery,那么这个元素就是jQuery元素,而不是jQLite元素。由于这个元素已经被jQuery/jQLite包装了,所以我们就在进行DOM操作的时候就不需要再使用 $()来进行包装。
attr – 一个包含了指令所在元素的属性的标准化的参数对象。举个例子,你给一个HTML元素添加了一些属性:,那么可以在 link 函数中通过 attrs.someAttribute 来使用它。

link函数主要用来为DOM元素添加事件监听、监视模型属性变化、以及更新DOM。在上面的指令代码片段中,我们添加了两个事件, click,和 mouseover。click 处理函数用来重置

的背景色,而 mouseover 处理函数改变鼠标为 pointer。在模板中有一个表达式 {{color}},当父scope中的 color 发生变化时,它用来改变 Hello World 文字的背景色。 这个 plunker 演示了这些概念。

compile函数

compile 函数在 link 函数被执行之前用来做一些DOM改造。它接收下面的参数:

tElement – 指令所在的元素
attrs – 元素上赋予的参数的标准化列表
要注意的是 compile 函数不能访问 scope,并且必须返回一个 link 函数。但是如果没有设置 compile 函数,你可以正常地配置 link 函数,(有了compile,就不能用link,link函数由compile返回)。compile函数可以写成如下的形式:

app.directive('test', function() {
return {
compile: function(tElem,attrs) {
//do optional DOM transformation here
return function(scope,elem,attrs) {
//linking function here
};
}
};
});
Copy after login

大多数的情况下,你只需要使用 link 函数。这是因为大部分的指令只需要考虑注册事件监听、监视模型、以及更新DOM等,这些都可以在 link 函数中完成。 但是对于像 ng-repeat 之类的指令,需要克隆和重复 DOM 元素多次,在 link 函数执行之前由 compile 函数来完成。这就带来了一个问题,为什么我们需要两个分开的函数来完成生成过程,为什么不能只使用一个?要回答好这个问题,我们需要理解指令在Angular中是如何被编译的!

指令是如何被编译的

当应用引导启动的时候,Angular开始使用 $compile 服务遍历DOM元素。这个服务基于注册过的指令在标记文本中搜索指令。一旦所有的指令都被识别后,Angular执行他们的 compile 方法。如前面所讲的,compile 方法返回一个 link 函数,被添加到稍后执行的 link 函数列表中。这被称为编译阶段。如果一个指令需要被克隆很多次(比如 ng-repeat),compile函数只在编译阶段被执行一次,复制这些模板,但是link 函数会针对每个被复制的实例被执行。所以分开处理,让我们在性能上有一定的提高。这也说明了为什么在 compile 函数中不能访问到scope对象。 在编译阶段之后,就开始了链接(linking)阶段。在这个阶段,所有收集的 link 函数将被一一执行。指令创造出来的模板会在正确的scope下被解析和处理,然后返回具有事件响应的真实的DOM节点。

改变指令的Scope

默认情况下,指令获取它父节点的controller的scope。但这并不适用于所有情况。如果将父controller的scope暴露给指令,那么他们可以随意地修改 scope 的属性。在某些情况下,你的指令希望能够添加一些仅限内部使用的属性和方法。如果我们在父的scope中添加,会污染父scope。 其实我们还有两种选择:

一个子scope – 这个scope原型继承子父scope。
一个隔离的scope – 一个孤立存在不继承自父scope的scope。
这样的scope可以通过指令定义对象中 scope 属性来配置。下面的代码片段是一个例子:

app.directive('helloWorld', function() {
return {
scope: true, 
// use a child scope that inherits from parent
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
Copy after login

上面的代码,让Angular给指令创建一个继承自父socpe的新的子scope。 另外一个选择,隔离的scope:

app.directive('helloWorld', function() {
return {
scope: {}, 
// use a new isolated scope
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
Copy after login

这个指令使用了一个隔离的scope。隔离的scope在我们想要创建可重用的指令的时候是非常有好处的。通过使用隔离的scope,我们能够保证我们的指令是自包含的,可以被很容易的插入到HTML应用中。 它内部不能访问父的scope,所保证了父scope不被污染。 在我们的 helloWorld 指令例子中,如果我们将 scope 设置成 {},那么上面的代码将不会工作。 它会创建一个新的隔离的scope,那么相应的表达式 {{color}} 会指向到这个新的scope中,它的值将是 undefined. 使用隔离的scope并不意味着我们完全不能访问父scope的属性。其实有一些技术可以允许我们访问父scope的属性,甚至监视他们的变化。我们会在指令这个系列的第二部分中讨论这些技术,以及一些更高级的概念,比如 Controller 函数。 第二部分也会和你一起使用Angular指令创建一个较为丰富的记事本应用。

关于AngularJS 中的指令实践指南(一),小编就给大家介绍到这里,下面文章讲给大家介绍angularjs中的指令实践开发指南二(二),希望对大家有所帮助!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Recommendations
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template