AngularJS指令用法详解

本文实例讲述了AngularJS指令用法。分享给大家供大家参考,具体如下:

指令(directives)是任何AngularJS应用中最重要的成分。尽管AngularJS已经自带了很多指令,你经常会发现需要自己亲手创建一些特别的指令。本文将会带你了解自定义指令并解释如何在现实世界中的Angular项目中使用它们。文章的最后,我们将一起用Angular指令来创建一个简单的笔记小应用。

综述

一个指令就是一个引入新语法的东西。指令是在DOM元素上做的标记,并同时附加了一些特定的行为。例如,静态的HTML并不知道如何来创建并显示一个日期选择插件。为了将这个新语法教给HTML我们需要一条指令。这个指令将会创建一个充当日期选择器的元素。我们将在随后看到如何实现这个指令。

如果你之前已经编写过Angular应用,那么你已经使用过指令了,不管你有没有意识到这点。你可能已经使用过像是ng-model,ng-repeat,ng-show等等这样的指令。所有这些指令都将特定的功能绑定到了DOM元素之上。例如,ng-repeat会重复特定的元素,而ng-show会有条件的展示元素。如果你想要创建一个可拖动元素的话你可能需要创建一个指令。指令背后的基本思想很简单。它通过在元素上绑定事件监听器并且将DOM变形来使HTML变得具有交互性。

从jQuery的角度来看指令

想想你如何使用jQuery来创建一个日期选择器。我们首先在HTML中添加一个普通的input字段然后在jQuery中我们调用$(element).dataPicker()来将其转换为一个日期选择器。但是,考虑一下。当一个设计师想要来检查这个标记时,他/她能够立刻猜出这个字段究竟是干什么用的吗?它仅仅是一个普通的input字段还是一个日期选择器?你必须要查看jQuery来确认这点。Angular的方法是使用指令来扩展HTML。因此,一个日期选择器的指令看上去可能如下所示:

<date-picker></date-picker>

或者如下所示:

<input type='text' data-picker/>

这种创建UI成分的方法既直观又清楚。你可以看到元素就知道它的用途。

创建自定义指令

一个Angular指令可能以四种形式出现:

1.一个新的HTML元素(<date-picker></date-picker>)

2.一个元素上的属性(<input type='text' date-picker/>)

3.作为一个类(<input type='text' class='date-picker'/>)

4.作为注释(<!--directive:date-picker-->)

当然,我们完全可以决定我们的指令以什么形式出现在HTML中。现在,我们来看看一个典型的Angular指令是如何写成的。它和controller的注册方式类似,但是它会返回一个简单的对象(指令定义),其中那个包含有一些配置指令的属性。下面的代码展示了一个简单和Hello World指令:

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

在上面的代码中,app.diretive()函数在我们的模块中注册了一个新的指令。这个函数的第一个参数是指令的名称。第二个参数是一个返回指令定义对象的函数。如果你的指令对额外的对象/服务(services)例如 $rootScope, $http 或者 $compile 有依赖,它们也可以在其中被注入。这个指令可以作为一个HTML元素来使用,如下所示:

<hello-world/>

或者:

<hello:world/>

或者作为一个属性来使用:

<div hello-world></div>

或者:

<div hello:world/>

如果你想要兼容HTML5,你可以在属性前面加上x-或者data-前缀。因此,下面的标记将会匹配helloWorld指令:

<div data‐hello‐world></div>

或者

<di vx‐hello‐world></div>

注意

当匹配指令时,Angular会从元素/属性名之前去除前缀x-或者data-。然后将分隔符 - 或者 : 转换为驼峰表示法已匹配注册的指令。这就是为什么我们的helloWorld指令用在HTML中的时候实际上写成了hello-world。

尽管上面的这个简单的指令仅仅只是展示了一些静态的文本,其中还是有一些值得我们去探究的有趣的点。我们已经在这个指令定义对象中使用了三个属性。我们来看看这三个属性分别都有什么用:

restrict - 这个属性指明了一个指令应该如何在HTML中使用(记住指令可以以四种方式出现)。在这个例子中我们将它设置为'AE'。因此,这条指令可以作为一个HTML元素或者一个属性来使用。为了允许指令作为一个类来使用我们可以将restrict设置为'AEC'。

template - 这个实行指明了当指令被Angular编译和链接时生成的HTML标记。它不一定是一个简单的字符串。template可以很复杂,其中经常会涉及其它的指令,表达式({{}}),等等。在大多数情况下你可能会想要使用templateUrl而不是template。因此,理想情况下你应该首先将模板放置在一个单独的HTML文件中然后让templateUrl指向它。

replace - 这个属性指明了是否生成的模板会代替绑定指令的元素。在前面的例子中我们在HTML中使用指令为<hello-world></hello-world>,并将replace属性设置为true。因此,在指令编译后,生成的模板代替了<hello-world></hello-world>。最后的输出结果是<h3>Hello World!</h3>。如果你将replace设置为false,默认情况下,输出模板将会被插入到指令被调用的元素中。

link函数和作用域

有一个指令生成的模板是没有用的除非它在正确的作用域中北编译。默认情况下一个指令并不会得到一个新的子作用域。然而,它可以得到父作用域。这意味着如果一个指令位于在一个控制器中那么它将使用控制器的作用域。

为了利用作用域,我们可以使用一个叫做link的函数。它可以通过指令定义对象中的link属性来配置。我们现在对helloworld指令做一些修改一遍当用户在一个input字段中输入一个颜色名称时,Hello Wolld文字的背景颜色会自动发生改变。同样,当一个用户点击Hello World文字时,背景颜色会重置为白色。相应的HTML标记如下所示:

<body ng-controller='MainCtrl'>
  <input type='text' ng-model='color' placeholder='Enter a color' / >
  <hello-wolrd/>
</body>

修改后的helloWorld指令代码如下所示:

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

注意到link函数被用在了指令中。它接收三个参数

scope - 它代表指令被使用的作用域。在上面的例子中它等同于符控制器的作用域。

elem - 它代表绑定指令的元素的jQlite(jQuery的一个自己)包裹元素。如果你在AngularJS被包含之前就包括了jQuery,那么它将变成jQuery包裹元素。由于该元素已经被jQuery/jQlite包裹,我们没有必要将它包含在$()中来进行DOM操作。

attars - 它代表绑定指令的元素上的属性。例如,如果你在HTML元素上有一些指令形式为:<hello-world some-attribute></hello-world>,你可以在link函数内用attrs.someAttribute来引用这些属性。

link函数主要是用来对DOM元素绑定事件监听器,监视模型属性变化,并更新DOM。在前面的指令代码中,我们绑定了两个监听器,click和mouseover。click处理函数重置了

的背景颜色,而mouseover处理函数则将游标改变为pointer。模板中拥有表达式{{color}},它将随着父作用域中的模型color的变化而变化,从而改变了Hello World的背景色。

Compile函数

Compile函数主要用来在link函数运行之前进行一些DOM转化。它接收下面几个参数:

tElement - 指令绑定的元素

attrs - 元素上声明的属性

这里要注意compile不能够访问scope,而且必须返回一个link函数。但是,如果没有compile函数以依然可以配置link函数。compile函数可以被写成下面的样子:

app.directive('test',function(){
  return {
    compile: function(tElem,attrs){
      //在这里原则性的做一些DOM转换
      return function(scope,elem,attrs){
       //这里编写link函数
      }
    }
  }
});

大多数时候,你仅仅只需要编写link函数。这是因为大部分指令都只关心与注册事件监听器,监视器,更新DOM等等,它们在link函数中即可完成。像是ng-repeat这样的指令,需要多次克隆并重复DOM元素,就需要在link函数运行之前使用compile函数。你可能会问威慑呢么要将两个函数分别使用。为什么我们不能只编写一个函数?为了回答这个问题我们需要理解Angular是如何编译指令的!

指令是如何被编译的

当应用在启动时,Angular开始使用$compile服务解析DOM。这项服务会在标记中寻找指令然后将它们各自匹配到注册的适龄。一旦所有的指令都已经被识别完成,Angular就开始执行它们的compile函数。正如前面所提到的,compile函数返回一个link函数,该函数会被添加到稍后执行的link函数队列中。这叫做编译阶段(compile phase)。注意到即使同一个指令有几个实例存在,compile函数也只会运行一次。

在编译阶段之后就到了链接阶段(link phase),这时link函数就一个接一个的执行。在这个阶段中模板被生成,指令被运用到正确的作用域,DOM元素上开始有了事件监听器。不像是compile函数,lin函数会对每个指令的实例都执行一次。

改变指令的作用域

默认情况下指令应该访问父作用域。但是我们并不像对所有情况一概而论。如果我们对指令暴露了父控制器的scope,那么指令就可以自由的修改scope属性。在一些情况下你的指令可能想要添加一些只有内部可以使用的属性和函数。如果我们都在父作用域中完成,可能会污染了父作用域。因此,我们有两种选择:

一个子作用域 - 这个作用域会原型继承父作用域。

一个隔离的作用域 - 一个全新的、不继承、独立存在的作用域。

作用域可以由指令定义对象中的scope属性定义。下面的例子展示了这一点:

app.directive('helloWorld',function(){
  return {
    scope: true, //使用一个继承父作用域的自作用域
    restrict: 'AE',
    replace: true,
    template: '<h3>Hello World!</h3>'
  }
});

上面的代码要求Angular为指令提供一个能够原型继承父作用域的子组用于。另一种情形,一个隔离作用域,代码如下所示:

app.directive('helloWorld',function(){
  return {
    scope: {}, //使用一个全新的隔离作用域
    restrict: 'AE',
    replace: true,
    template: '<h3>Hello World!</h3>'
  }
});

上面的指令使用一个不继承父作用域的全新隔离作用域。当你想要创建一个可重用的组件时隔离作用域是一个很好的选择。通过隔离作用域我们确保指令是自包含的兵可以轻松地插入到任何HTML app中。这种做法防止了父作用域被污染,由于它不可访问父作用域。在我们修改后的helloWorld指令中如果你将scope设置为{},那么代码就不会再正常运行。它将创建一个隔离的作用域然后表达式{{color}}将无法引用隔离作用域中的属性因此值变为undefined。

隔离作用域并不意味着你一点都不能获取到父作用域中的属性。有一些技巧可以使你访问父作用域中的属性同时监听这些属性的变化。我们将在后续文章中提到这种高级技巧。

希望本文所述对大家AngularJS程序设计有所帮助。

(0)

相关推荐

  • AngularJS使用自定义指令替代ng-repeat的方法

    前言 大家都知道对于处理小数量,ng-repeat是非常有用的,但是如果需要处理非常大的数量集,还是采用自定义的方法更好一些.特别是数据大多都是静态的或已预存储好的,这个时候应避免使用ng-repeat指令. ng-repeat中的表达式和 $watch Angular中的表达式都会创建$watch 的Scope 函数.用于监听模型变化,当你的模型部分发生变化时它会通知你.在ng-repeat指令中,如果某行数据有15列数据都绑定了表达式,如果数据有1000多行的话,那么$watch就又奖金15

  • AngularJS中关于ng-class指令的几种实现方式详解

    前言 开发中经常会遇到这样的需求,一个元素需要在不同的状态下呈现不同的样子,而在这所谓的的样子当然就是改变其css的属性,而实现动态的改变属性值,我们就需要实现动态的更换其class属性值. 在这给大家介绍三种方法来实现,大家可以根据自己的需求来选择方式,下面来看看. 第一种:通过数据的双向绑定(不推荐) <div ng-controller="firstController"> <div ng-class="{{className}}">&

  • AngularJS用户选择器指令实例分析

    本文实例分析了AngularJS用户选择器指令.分享给大家供大家参考,具体如下: 在开发表单时,我们需要使用经常需要使用到用户选择器,用户的数据一般使用如下方式存储: 用户1,用户2,用户3 我们可以使用angular指令实现选择器. <!DOCTYPE html> <html ng-app="app"> <head> <meta charset="UTF-8"> <meta http-equiv="c

  • AngularJS中指令的四种基本形式实例分析

    本文实例讲述了AngularJS中指令的四种基本形式.分享给大家供大家参考,具体如下: 指令的四种基本形式中, 注意注释型指令 M 的使用方法是 <!--  directive:指令名称  --> 注意左右俩测必须有空格才会正常识别 所有指令是可以相互组合 的,不写restrict ,将会默认为A属性 指令要支持IE8 浏览器 一般最好将指令设置为属性 <!doctype html> <html ng-app="myapp"> <head>

  • 详解AngularJS中ng-src指令的使用

    前言 在日常开发工作中,有很多需求是在一个页面上显示一些图片.有时,图片的地址路径是由客户端的脚本来设置(它有可能是从数据库中获取的). 这是Angularjs的时代,当我们想使用Angularjs来实现在页面中展示图片,我们会简单使用: <img src="path of image">. 如果我们只考虑展示,毫无疑问它没问题,但是在浏览器的控制台中会显示一个 404 (not found) 错误. 为了解决这个问题,我们需要使用ng-Src.在使用 ng-Src之前,我

  • AngularJS 自定义指令详解及实例代码

    AngularJS支持用户自定义标签属性,在不需要使用DOM节点操作的情况下,添加自定义的内容. 前面提到AngularJS的四大特性: 1 MVC 2 模块化 3 指令 4 双向数据绑定 下面将会介绍如下的内容: 1 如何自定义指令 2 自定义指令的使用 3 自定义指令的内嵌使用 如何自定义指令: Angular是基于模块的框架,因此上来肯定要创建一个自己的模块: var myAppModule = angular.module("myApp",[]); 然后在此模块基础上创建指令d

  • AngularJS创建自定义指令的方法详解

    本文实例讲述了AngularJS创建自定义指令的方法.分享给大家供大家参考,具体如下: 这是一篇译文,来自angular开发者说明的指令.主要面向已经熟悉angular开发基础的开发者.这篇文档解释了什么情况下需要创建自己的指令,和如何去创建指令. 什么是指令 从一个高的层面来讲,指令是angular $compile服务的说明,当特定的标签(属性,元素名,或者注释) 出现在DOM中的时候,它让编译器附加指定的行为到DOM上. 这个过程是很简单的.angular内部有很用这样自带的指令,比如说n

  • AngularJS递归指令实现Tree View效果示例

    本文实例讲述了AngularJS递归指令实现Tree View效果的方法.分享给大家供大家参考,具体如下: 在层次数据结构展示中,树是一种极其常见的展现方式.比如系统中目录结构.企业组织结构.电子商务产品分类都是常见的树形结构数据. 这里我们采用Angular的方式来实现这类常见的tree view结构. 首先我们定义数据结构,采用以children属性来挂接子节点方式来展现树层次结构,示例如下: [ { "id":"1", "pid":&quo

  • AngularJS封装指令方法详解

    本文实例讲述了AngularJS封装指令方法.分享给大家供大家参考,具体如下: 引言:angularjs是一个中等重量级的前端开发框架 HTML是一门很好的为静态文本设计的语言,但要构建动态的web应用它就显的乏力了.通常,我们使用以下技术来解决静态网页技术在构建动态应用上的不足: 1.类库:类库是一类函数的集合,它能帮助你写web应用.这里起主导作用是你的代码,由你来决定何时使用类库.典型的类库,例如prototype.jQuery等. 2.框架:框架式一种特殊的.已经实现的web应用,你只需

  • 浅谈AngularJs指令之scope属性详解

    AngularJS使用directive()方法类定义一个指令: .directive("name",function(){ return{ }; }) 上面是定义一个指令的主体框架,该方法接受两个参数: 1.第一个参数:name表示定义的指令的名称(angularjs会用这个name注册这个指令) 2.第二个参数:函数,该番薯必须返回一个对象或者一个函数,但通常我们会返回一个对象.return后接的就是返回的对象. 在返回的对象中有一个scope属性,这个属性用来修饰指令的作用域.

随机推荐