AngularJs 指令详解及示例代码

对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能。

首先来看个完整的参数示例再来详细的介绍各个参数的作用及用法:

angular.module('myApp', [])
.directive('myDirective', function() {
  return {
    restrict: String,
    priority: Number,
    terminal: Boolean,
    template: String or Template Function:
  function(tElement, tAttrs) {...},
  templateUrl: String,
  replace: Boolean or String,
  scope: Boolean or Object,
  transclude: Boolean,
  controller: String or
  function(scope, element, attrs, transclude, otherInjectables) { ... },
  controllerAs: String,
  require: String,
  link: function(scope, iElement, iAttrs) { ... },
  compile: // 返回一个对象或连接函数,如下所示:
  function(tElement, tAttrs, transclude) {
    return {
      pre: function(scope, iElement, iAttrs, controller) { ... },
      post: function(scope, iElement, iAttrs, controller) { ... }
      }
    return function postLink(...) { ... }
    }
  };
 });

restrict[string]

restrict是一个可选的参数。用于指定该指令在DOM中以何种形式被声明。默认值是A,即以属性的形式来进行声明。
可选值如下:

E(元素)

<my-directive></my-directive>

A(属性,默认值)

<div my-directive="expression"></div>

C(类名)

<div class="my-directive:expression;"></div>

M(注释)

<--directive:my-directive expression-->

一般考虑到浏览器的兼容性,强烈建议使用默认的属性就可以即即以属性的形式来进行声明。最后一种方式建议再不要求逼格指数的时候千万不要用。

Code:

 angular.module('app',[])
  .directive('myDirective', function () {
      return {
        restrict: 'E',
        template: '<a href="http://www.baidu.com">百度</a>'
      };
    })
HtmlCode:
 <my-directive></my-directive>

效果:

priority[int]

大多数指令会忽略这个参数,使用默认值0,但也有些场景设置高优先级是非常重要甚至是必须的。例如,ngRepeat将这个参数设置为1000,这样就可以保证在同一元素上,它总是在其他指令之前被调用。

terminal[bool]

这个参数用来停止运行当前元素上比本指令优先级低的指令。但同当前指令优先级相同的指令还是会被执行。
例如:ngIf的优先级略高于ngView(它们操控的实际就是terminal参数),如果ngIf的表达式值为true,ngView就可以被正常执行,但如果ngIf表达式的值为false,由于ngView的优先级较低就不会被执行。

template[string or function]

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

一段HTML文本;

一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串。tElement和tAttrs中的t代表template,是相对于instance的。

首先演示下第二种用法:

angular.module('app',[])
  .directive('myDirective', function () {
      return {
        restrict: 'EAC',
        template: function (elem, attr) {
          return "<a href='" + attr.value + "'>" + attr.text + "</a>";
        }
    };
  })

HtmlCode:(效果同上,不做演示了)

<my-directive value="http://www.baidu.com" text="百度"></my-directive>
    <div my-directive
       value="http://www.baidu.com"
       text="百度"></div>

templateUrl[string or function]

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

一个代表外部HTML文件路径的字符串;

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

无论哪种方式,模板的URL都将通过ng内置的安全层,特别是$getTrustedResourceUrl,这样可以保护模板不会被不信任的源加载。 默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件。加载大量的模板将严重拖慢一个客户端应用的速度。为了避免延迟,可以在部署应用之前对HTML模板进行缓存。

Code:

 angular.module('app',[])
  .directive('myDirective', function () {
      return {
        restrict: 'AEC',
        templateUrl: function (elem, attr) {
          return attr.value + ".html"; //当然这里我们可以直接指定路径,同时在模板中可以包含表达式
        }
    };
  })

replace[bool]

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

例如上面的示例默认值情况下,生成的html代码如下:

<my-directive value="http://www.baidu.com" text="百度"><a href="http://www.baidu.com">百度</a></my-directive>

如果设置replace=true

<a href="http://www.baidu.com" value="http://www.baidu.com" text="百度">百度</a>

据我观察,这种效果只有设置restrict="E"的情况下,才会表现出实际效果。

介绍完基本的指令参数后,就要涉及到更重要的作用域参数了...

scope参数[bool or object]

scope参数是可选的,可以被设置为true或一个对象。默认值是false。

如果一个元素上有多个指令使用了隔离作用域,其中只有一个可以生效。只有指令模板中的根元素可以获得一个新的作用域。因此,对于这些对象来说scope默认被设置为true。内置指令ng-controller的作用,就是从父级作用域继承并创建一个新的子作用域。它会创建一个新的从父作用域继承而来的子作用域。这里的继承就不在赘述,和面向对象中的继承基本是一直的。

首先我们来分析一段代码:

    <div ng-app="app" ng-init="name= '祖父'">
      <div ng-init="name='父亲'">
        第一代:{{ name }}
        <div ng-init="name= '儿子'" ng-controller="SomeController">
          第二代: {{ name }}
          <div ng-init="name='孙子'">
            第三代: {{ name }}
          </div>
        </div>
      </div>
    </div> 

我们发现第一代,我们初始化name为父亲,但是第二代和第三代其实是一个作用域,那么他们的name其实是一个对象,因此出现的效果如下:

第一代:父亲
第二代: 孙子
第三代: 孙子

我们在修改一下代码,把第三代隔离开来再看看效果:

 <div ng-app="app"ng-init="name= '祖父'">
      <div ng-init="name='父亲'">
        第一代:{{ name }}
        <div ng-init="name= '儿子'" ng-controller="SomeController">
          第二代: {{ name }}
          <div ng-init="name='孙子'" ng-controller="SecondController">
            第三代: {{ name }}
          </div>
        </div>
      </div>
    </div>

angular.module('app', [])
    .controller('SomeController',function($scope) {

    })
    .controller('SecondController', function ($scope) {

  })

效果如下:

第一代:父亲
         第二代: 儿子
         第三代: 孙子

在修改下代码来看看继承:

    <div ng-app="app"ng-init="name= '祖父的吻'">
      <div>
        第一代:{{ name }}
        <div ng-controller="SomeController">
          第二代: {{ name }}
          <div ng-controller="SecondController">
            第三代: {{ name }}
          </div>
        </div>
      </div>
    </div> 

效果如下:

第一代:祖父的吻
第二代: 祖父的吻
第三代: 祖父的吻

如果要创建一个能够从外部原型继承作用域的指令,将scope属性设置为true,简单来说就是可继承的隔离,即不能反向影响父作用域。

再来看个例子:

angular.module('myApp', [])
    .controller('MainController', function ($scope) {
    })
    .directive('myDirective', function () {
      return {
        restrict: 'A',
        scope:false,//切换为{},true测试
        priority: 100,
        template: '<div>内部:{{ myProperty }}<input ng-model="myProperty"/></div>'
      };
    });

Html代码:

 <div ng-controller='MainController' ng-init="myProperty='Hello World!'">
    外部: {{ myProperty}}
    <input ng-model="myProperty" />
    <div my-directive></div>
  </div>

当我们改变scope的值我们会发现

false:继承但不隔离

true:继承并隔离

{}:隔离且不继承

 transclude

transclude是一个可选的参数。默认值是false。嵌入通常用来创建可复用的组件,典型的例子是模态对话框或导航栏。我们可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象。为了将作用域传递进去,scope参数的值必须通过{}或true设置成隔离作用域。如果没有设置scope参数,那么指令内部的作用域将被设置为传入模板的作用域。

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

我们来看两个例子-导航栏:

  <div side-box title="TagCloud">
    <div class="tagcloud">
      <a href="">Graphics</a>
      <a href="">ng</a>
      <a href="">D3</a>
      <a href="">Front-end</a>
      <a href="">Startup</a>
    </div>
  </div>

JsCode:

 angular.module('myApp', [])
 .directive('sideBox', function() {
   return {
     restrict: 'EA',
     scope: {
       title: '@'
     },
     transclude: true,
     template: '<div class="sidebox"><div class="content"><h2 class="header">' +
       '{{ title }}</h2><span class="content" ng-transclude></span></div></div>'
     };
  });

这段代码告诉ng编译器,将它从DOM元素中获取的内容放到它发现ng-transclude指令的地方。

再来你看个官网的例子:

angular.module('docsIsoFnBindExample', [])
 .controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
  $scope.name = 'Tobias';
  $scope.hideDialog = function () {
   $scope.dialogIsHidden = true;
   $timeout(function () {
    $scope.dialogIsHidden = false;
   }, 2000);
  };
 }])
 .directive('myDialog', function() {
  return {
   restrict: 'E',
   transclude: true,
   scope: {
    'close': '&onClose'
   },
   templateUrl: 'my-dialog-close.html'
  };
 });

my-dialog-close.html

my-dialog-close.html
<div class="alert">
 <a href class="close" ng-click="close()">×</a>
 <div ng-transclude></div>
</div>

indext.html

<div ng-controller="Controller">
 <my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
  Check out the contents, {{name}}!
 </my-dialog>
</div>

如果指令使用了transclude参数,那么在控制器无法正常监听数据模型的变化了。建议在链接函数里使用$watch服务。

 controller[string or function]

controller参数可以是一个字符串或一个函数。当设置为字符串时,会以字符串的值为名字,来查找注册在应用中的控制器的构造函数.

angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A',
controller: 'SomeController'
})

可以在指令内部通过匿名构造函数的方式来定义一个内联的控制器

angular.module('myApp',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器逻辑放在这里
}
});

我们可以将任意可以被注入的ng服务注入到控制器中,便可以在指令中使用它了。控制器中也有一些特殊的服务可以被注入到指令当中。这些服务有:

1. $scope

与指令元素相关联的当前作用域。

2. $element

当前指令对应的元素。

3. $attrs

由当前元素的属性组成的对象。

<div id="aDiv"class="box"></div>
具有如下的属性对象:
{
id: "aDiv",
class: "box"
}

4. $transclude

嵌入链接函数会与对应的嵌入作用域进行预绑定。transclude链接函数是实际被执行用来克隆元素和操作DOM的函数。

angular.module('myApp',[])
 .directive('myLink', function () {
   return {
     restrict: 'EA',
     transclude: true,
     controller:
     function ($scope, $element,$attrs,$transclude) {
       $transclude(function (clone) {
         var a = angular.element('<a>');
         a.attr('href', $attrs.value);
         a.text(clone.text());
         $element.append(a);
       });
     }
   };
 });

html

<my-link value="http://www.baidu.com">百度</my-link>
    <div my-link value="http://www.google.com">谷歌</div>

仅在compile参数中使用transcludeFn是推荐的做法。link函数可以将指令互相隔离开来,而controller则定义可复用的行为。如果我们希望将当前指令的API暴露给其他指令使用,可以使用controller参数,否则可以使用link来构造当前指令元素的功能性(即内部功能)。如果我们使用了scope.$watch()或者想要与DOM元素做实时的交互,使用链接会是更好的选择。使用了嵌入,控制器中的作用域所反映的作用域可能与我们所期望的不一样,这种情况下,$scope对象无法保证可以被正常更新。当想要同当前屏幕上的作用域交互时,可以使用传入到link函数中的scope参数。

controllerAs[string]

controllerAs参数用来设置控制器的别名,这样就可以在视图中引用控制器甚至无需注入$scope。

<div ng-controller="MainController as main">
    <input type="text" ng-model="main.name" />
    <span>{{ main.name }}</span>
  </div> 

JsCode:

angular.module('myApp',[])
  .controller('MainController', function () {
    this.name = "Halower";
  });

控制器的别名使路由和指令具有创建匿名控制器的强大能力。这种能力可以将动态的对象创建成为控制器,并且这个对象是隔离的、易于测试。

 require[string or string[]]

require为字符串代表另外一个指令的名字。require会将控制器注入到其所指定的指令中,并作为当前指令的链接函数的第四个参数。字符串或数组元素的值是会在当前指令的作用域中使用的指令名称。在任何情况下,ng编译器在查找子控制器时都会参考当前指令的模板。

  1. 如果不使用^前缀,指令只会在自身的元素上查找控制器。指令定义只会查找定义在指令作当前用域中的ng-model=""
  2. 如果使用?前缀,在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数。
  3. 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器。
  4. 如果添加了?^ 将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找
  5. 如果没有任何前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误

compile【object or function】

compile选项本身并不会被频繁使用,但是link函数则会被经常使用。本质上,当我们设置了link选项,实际上是创建了一个postLink() 链接函数,以便compile() 函数可以定义链接函数。通常情况下,如果设置了compile函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。

compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。

编译函数负责对模板DOM进行转换。链接函数负责将作用域和DOM进行链接。 在作用域同DOM链接之前可以手动操作DOM。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。

link

compile: function(tEle, tAttrs, transcludeFn) {
 //todo:
 return function(scope, ele, attrs) {
 // 链接函数
 };

链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。

ngModel

它提供更底层的API来处理控制器内的数据,这个API用来处理数据绑定、验证、 CSS更新等不实际操作DOM的事情,ngModel 控制器会随 ngModel 被一直注入到指令中,其中包含了一些方法。为了访问ngModelController必须使用require设置.

ngModelController常用的元素如下:

1.为了设置作用域中的视图值,需要调用 ngModel.$setViewValue() 函数。
$setViewValue() 方法适合于在自定义指令中监听自定义事件(比如使用具有回调函数的jQuery插件),我们会希望在回调时设置$viewValue并执行digest循环。

angular.module('myApp')
    .directive('myDirective', function() {
      return {
        require: '?ngModel',
        link: function(scope, ele, attrs, ngModel) {
          if (!ngModel) return;
          $(function() {
            ele.datepicker({
               //回调函数
              onSelect: function(date) {
                // 设置视图和调用 apply
                scope.$apply(function() {
                  ngModel.$setViewValue(date);
                });
              }
            });
          });
        }
      };
    });

2.$render方法可以定义视图具体的渲染方式

3.属性

1. $viewValue

$viewValue属性保存着更新视图所需的实际字符串。

2. $modelValue

$modelValue由数据模型持有。 $modelValue和$viewValue可能是不同的,取决于$parser流水线是否对其进行了操作。

3. $parsers

$parsers 的值是一个由函数组成的数组,其中的函数会以流水线的形式被逐一调用。ngModel 从DOM中读取的值会被传入$parsers中的函数,并依次被其中的解析器处理。

4. $formatters

$formatters的值是一个由函数组成的数组,其中的函数会以流水线的形式在数据模型的值发生变化时被逐一调用。它和$parser流水线互不影响,用来对值进行格式化和转换,以便在绑定了这个值的控件中显示。

5. $viewChangeListeners

$viewChangeListeners的值是一个由函数组成的数组,其中的函数会以流水线的形式在视图中的值发生变化时被逐一调用。通过$viewChangeListeners,可以在无需使用$watch的情况下实现类似的行为。由于返回值会被忽略,因此这些函数不需要返回值。

6. $error

$error对象中保存着没有通过验证的验证器名称以及对应的错误信息。

7. $pristine

$pristine的值是布尔型的,可以告诉我们用户是否对控件进行了修改。

8. $dirty

$dirty的值和$pristine相反,可以告诉我们用户是否和控件进行过交互。

9. $valid

$valid值可以告诉我们当前的控件中是否有错误。当有错误时值为false, 没有错误时值为true。

10. $invalid

$invalid值可以告诉我们当前控件中是否存在至少一个错误,它的值和$valid相反。

以上就是关于AngularJS的指令知识资料整理,后续继续补充,谢谢大家对本站的支持!

(0)

相关推荐

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

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

  • angularJS 中$scope方法使用指南

    复制代码 代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> <title>无标题文档</title> </head> <script src="http://localhost:81/js/jquery.js"> </script> <script src="http://lo

  • angularjs 源码解析之scope

    简介 在ng的生态中scope处于一个核心的地位,ng对外宣称的双向绑定的底层其实就是scope实现的,本章主要对scope的watch机制.继承性以及事件的实现作下分析. 监听 1. $watch 1.1 使用 // $watch: function(watchExp, listener, objectEquality) var unwatch = $scope.$watch('aa', function () {}, isEqual); 使用过angular的会经常这上面这样的代码,俗称"手

  • AngularJs Scope详解及示例代码

    一.什么是Scope? scope(http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope)是一个指向应用model的object.它也是expression(http://www.cnblogs.com/lcllao/archive/2012/09/16/2687162.html)的执行上下文.scope被放置于一个类似应用的DOM结构的层次结构中.scope可以监测(watch,$watch)expression和传播事件.

  • AngularJS指令详解及示例代码

    AngularJS指令用于扩展HTML.这些都是先从ng- 前缀的特殊属性.我们将讨论以下指令: ng-app - 该指令启动一个AngularJS应用. ng-init - 该指令初始化应用程序数据. ng-model - 此指令定义的模型,该模型是变量在AngularJS使用. ng-repeat - 该指令将重复集合中的每个项目的HTML元素. ng-app指令 ng-app 指令启动一个AngularJS应用.它定义根元素.它会自动初始化或启动加载包含AngularJS应用程序的Web页

  • AngularJs 指令详解及示例代码

    对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能. 首先来看个完整的参数示例再来详细的介绍各个参数的作用及用法: angular.module('myApp', []) .directive('myDirective', function() { return { restrict: String, priority: Number, terminal: Boolean, template: String or Template Function: func

  • AngularJs bootstrap详解及示例代码

    AngularJs学习笔记系列第一篇,希望我可以坚持写下去.本文内容主要来自 http://docs.angularjs.org/guide/ 文档的内容,但也加入些许自己的理解与尝试结果. 一.总括 本文用于解释Angular初始化的过程,以及如何在你有需要的时候对Angular进行手工初始化. 二.Angular <script> 标签 本例用于展示如何通过推荐的路径整合Angular,实现自动初始化. <!doctype html> <html xmlns:ng=&qu

  • AngularJS基础 ng-model 指令详解及示例代码

    AngularJS ng-model 指令 AngularJS 实例 绑定输入框的值到 scope 变量中: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </hea

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

    自定义指令中使用AngularJS扩展HTML的功能.自定义指令使用的"指令"的功能定义.自定义指令只是替换了它被激活的元素.引导过程中AngularJS应用程序找到了匹配的元素,并做好使用自定义指令compile()方法一次活动再处理使用基于指令的范围自定义指令link()方法的元素. AngularJS提供支持,以下列元素的类型来创建自定义指令. Element directives - 指令遇到时激活一个匹配的元素. Attribute - - 指令遇到时激活一个匹配的属性. C

  • AngularJS基础 ng-list 指令详解及示例代码

    AngularJS ng-list 指令 AngularJS 实例 转换用户的输入为数组: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <

  • AngularJS模块详解及示例代码

    AngularJS支持模块化的方法.模块用于单独的逻辑表示服务,控制器,应用程序等,并保持代码的整洁.我们在单独的js文件中定义的模块,并将其命名为按照module.js文件形式.在这个例子中,我们要创建两个模块. Application Module - 用于初始化控制器应用程序 Controller Module - 用于定义控制器 应用模块 mainApp.js var mainApp = angular.module("mainApp", []); 在这里,我们已经声明使用 a

  • AngularJS表格详解及示例代码

    格数据本质上通常是重复的.ng-repeat指令,可以用来方便地绘制表格.下面的示例说明使用ng-repeat指令来绘制表格. <table> <tr> <th>Name</th> <th>Marks</th> </tr> <tr ng-repeat="subject in student.subjects"> <td>{{ subject.name }}</td>

  • AngularJS国际化详解及示例代码

    AngularJS支持内置的国际化三种类型的过滤器货币,日期和数字.只需要根据国家的区域纳入相应的JS.默认情况下它处理浏览器的语言环境.例如,要使用丹麦语的语言环境,使用下面的脚本 <script src="https://code.angularjs.org/1.2.5/i18n/angular-locale_da-dk.js"></script> 使用丹麦语的语言环境实例 testAngularJS.html <html> <head&g

  • AngularJS过滤器详解及示例代码

    过滤器是用来更改修改数据,并且可以在表达式或使用管道符指令将其归入.以下是常用的过滤器的列表. S.No. 名称 描述 1 大写 转换文本为大写文本. 2 小写 转换文本为小写文本. 3 货币 货币格式格式文本. 4 过滤器 过滤数组中它根据所提供的标准的一个子集. 5 排序 排序提供标准的基础数组. 大写过滤器 添加大写的过滤器使用管道符的表达式.在这里,添加了大写过滤器,全部用大写字母打印学生姓名. Enter first name:<input type="text" ng

随机推荐