欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Angular中的自定义指令

程序员文章站 2022-04-24 16:45:35
...

什么是指令?

  • 百度上是这样定义的:
    • 指令是指示计算机执行某种操作的命令,它由一串二进制数码组成
  • 当然我们这里并不是深究这个概念的,下面主要讲讲Angular中的指令:
    • AngularJS中的指令是对 HTML 标签属性的扩展,比如说为 DOM 元素调用方法、定义行为绑定数据等;
    • AngularJS最大程度减少DOM操作,实现数据绑定,与业务逻辑进行交互,其本质上就是AngularJS扩展了具有自定义功能的HTML元素;
    • 指令就是DOM逻辑行为的媒介,本质就是DOM绑定的独立逻辑行为函数调用指令意味着执行指令背后与之相关联的JavaScript代码,这些代码是我们用指令定义写出来的;
    • 值得一说的是,AngularJS与jQuery的区别?
      • jq大量操作DOM,而ng则避免操作DOM
      • 我个人理解ng的MVC的开发思想,还是在于指令封装了一系列操作DOM的操作,只是我们看不到,ng最大的亮点在数据双向绑定,实质就是DOM的操作形式不一样。
      • JQuery通过选择器找到DOM元素,再赋予元素的行为;
        而AngularJS则是,将指令与DOM绑定在一起,再扩展指令的行为。

指令怎么创建?

  1. 我们可以通过AngularJS模块API中的内置的.directive()方法
  2. 通过传入一个字符串,用来定义指令名称一个函数,也就是这个指令要实现某种功能对应的一段html代码来注册一个新指令。
  • 其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,
  • 函数应该返回一个对象

自定义指令的写法

  • 使用.directive()方法
  • return 一个对象,这个对象可以完成某些功能
  • 参数都有那些,什么含义
angular.module('app', [])
.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(...) { ... }
        }
    };
 });

关于参数可以分三大类

  1. 描述指令或DOM本身特性的内部参数
  2. 连接指令外界、与其他指令或控制器沟通的对外参数
  3. 描述指令本身行为的行为参数

常用的内部参数及其含义:

  • restrict:String,可以为EAMC的任何一种,也可以混搭,它指明了指令是以什么方式来使用
  • priority: Number,指令执行优先级
  • template: String,指令链接DOM模板,例如<h1>{{head}}</h1>
  • templateUrl:String,DOM模板路径
  • replace: Boolean,指令链接模板是否替换原有元素,

下面是关于这些参数的详细解释

restrict: String,

  • 指明这个指令是以什么形式被声明;

    • A 是Attribute,以属性形式使用
      <div my-directive></div>

    • E 是Element,以标签形式使用<my-directive></my-directive>

    • C 是class,以类名形式使用<div class="my-directive"></div>

    • M 是Commons,以注释形式使用,不建议使用<--directive: my-directive-->

  • 这些选项可以单独使用,也可以混合在一起使用:

举个栗子: 定义一个my-directive的指令,指定以标签和属性形式使用:

    angular.module('myApp', [])
           .directive('myDirective', function(){
                return {
                    restrict: 'EA' // 输入元素或属性
            }
    })

priority: Number,

  • 设置优先级的,可忽略不写,默认值为0,这样就可以保证在同一元素上,它总是在其他指令之前被调用。

terminal: Boolean,

  • 属性值为布尔型,也就是true或false,
    • 如果为false,则这个参数用来告诉AngularJS停止运行当前元素上比本指令优先级低的指令。
    • 优先级相同的指令还是会被执行。

template: String or Template Function:

  • 属性值为一段字符串或者是一个函数,必须被设置其中一种

    • 一段HTML文本;
    • 可以接收两个参数的函数,参数为 tElement 和 tAttrs
    • 注意:
      在html模板中必须只有一个根html标签,且如果有换行则需要使用“\”
  • 举个栗子:

template: '\
     <div> <--div作为它的根节点 -->\
        <a href="http://blog.zhouminghang.xyz">我的博客地址</a>\
        <h1>多个标签时,要使用同一个根节点包裹</h1>\
     </div>\'
          

templateUrl: String,

  • 字符串或函数
    • 外部路径的字符串,
    • 接受两个参数的函数,参数为 tElement 和 tAttrs ,并返回一个外部HTML文件路径的字符串
    • 模板加载后,AngularJS会将它默认缓存到 $templateCache 服务中。(可以提前加载模块到缓存中,提高加载速度)

replace: Boolean or String,

  • 为false时模板内容会加载到标签内部;
    • 如果不设置,默认为false;
  • 为true,模板内容会替换当前标签,也就是在页面中没有指令,只有替换模板;

scope: Boolean or Object,
*(布尔型或对象),默认为false

  • 设置为true 时,会从父作用域继承并创建一个新的作用域对象。
  • ng-controller 的作用,就是从父级作用域继承并创建一个新的子作用域。
  • 如果要创建一个能够从外部原型继承作用域的指令,将 scope 属性设置为 true
  • 设置为一个对象,则设置了一个隔离的作用域。
    * 如果scope属性设置为一个空对象{},指令的模板就无法访问外部作用域
.directive('myDirective', function() {
                  return {
                        restrict: 'A',
                        scope: {},
                        priority: 100,
                        template: '<div>Inside myDirective {{ myProperty }}</div>'
                   };
                });
            
  • 在scope对象中,还可以使用“@” “=” “&”,来设置模板中数据的作用域和绑定规则
    • "@" 本地作用域属性:使用当前指令中的数据和DOM属性的值进行绑定
    • “=” 双向绑定:本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。
    • “&” 父级作用域绑定:通过 & 符号可以对父级作用域进行绑定
      举个栗子:
scope: {
   ngModel: '=', // 将ngModel同指定对象绑定
   onSend: '&', // 将引用传递给这个方法
   fromName: '@' // 储存与fromName相关联的字符串
}

transclude: Boolean,

  • 默认为false.
  • 只有当你希望创建一个可以包含任意内容的指令时,才使用transclude: true ;

注意:
如果指令使用了 transclude 参数,那么在控制器中就无法正常监听数据模型的变化了。


controller: String or function(scope, element, attrs, transclude, otherInjectables) { ... },

  • 字符串或函数,注册在应用中的控制器的构造函数
  • 使用函数创建内联控制器,
angular.module('myApp',[])
    .directive('myDirective', function() {
    restrict: 'A',
    controller:
    function($scope, $element, $attrs, $transclude) {
    // 控制器逻辑放在这里
   }
})

controllerAs: String,

  • 用来在指令中创建匿名控制器;
  • 类似于设置别名;
    举个栗子:
.directive('myDirective', function() {
    return {
    restrict: 'A',
    template: '<h4>{{ myController.msg }}</h4>',
    controllerAs: 'myController',
    controller: function() {
        this.msg = "Hello World"
        }
    };
});  

require: String,

  • 字符串或数组
  • 字符串代表另外一个指令的名字,如果没有前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误。
  • 如果不使用 ^ 前缀,指令只会在自身的元素上查找控制器。
require: 'ngModel'
  • 使用 ?
    • 如果在当前指令中没有找到所需要的控制器,会将 null 作为传给 link 函数的第四个参数
require: '?ngModel'
  • 使用 ^
    • 如果添加了 ^ 前缀,指令会在上游的指令链中查找 require 参数所指定的控制器。
require: '^ngModel'
  • 使用 ^?
    • 将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找。
require: '^?ngModel',

link: function(scope, iElement, iAttrs) { ... },

  • compile 选项本身并不会被频繁使用,但是 link 函数则会被经常使用。
  • 当我们设置了 link 选项, 实际上是创建了一个 postLink() 链接函数, 以便 compile() 函数可以定义链接函数。
  • compile 和 link 选项是互斥的。如果同时设置了这两个选项,那么会把 compile所返回的函数当作链接函数,而 link 选项本身则会被忽略。
  • 通常情况下,如果设置了 compile 函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。
  • 用 link 函数创建可以操作DOM的指令。
require 'SomeController',
link: function(scope, element, attrs, SomeController) {
     //在这里操作DOM,可以访问required指定的控制器
}
compile: function(tElement, tAttrs, transclude) {  
    return {
            pre: function(scope, iElement, iAttrs, controller) { ... },
            post: function(scope, iElement, iAttrs, controller) { ... }
                }
    // 或者
                return function postLink(...) { ... }
            }
        };
});