Angular - 指令

前言

使用指令的优势在于,我们无需太多关心指令的内部实现(当给 Angular 应用添加所需指令后,Angular 内部会自行编译和运行所有指令),只需把重点放在如何使用指令上即可。

对于指令,我们需要了解一下几个问题:

  1. 什么是指令?
  2. 如何创建指令?
  3. 指令是如何编译和运行的?

什么是指令?

指令就是 AngularJS 扩展具有自定义功能的 HTML 元素的途径,指令又分为内置指令和自定义指令。

内置指令

AngularJS 提供了一系列的内置指令。其中一些指令重载了原生 HTML 元素,比如:

标签,当在 HTML 中使用标签时,并不一定可以明确看出是否在使用指令。

基础 ng 属性指令
布尔属性

根据 HTML 标准的定义,布尔属性代表了 truefalse。当这个属性出现时即为 true,未出现为 false。AngularJS 提供了一组布尔属性,通过表达式的值来判断是否在元素上插入或移除该属性。

  1. ng-disabled
    使用 ng-disabled 可以对 disabled 属性进行绑定。
  2. ng-readonly
    使用 ng-readonly 可以对 readonly 属性进行绑定。
  3. ng-checked
    使用 ng-checked 可以对 checked 属性进行绑定。
  4. ng-selected
    使用 ng-selected 可以对 option 标签中的 selected 属性进行绑定。
  

ng-checked = true

ng-checked = false

angular.module('myApp', [])
        .controller('MyApp', ['$scope', function ($scope) {
            $scope.isDisabled = true;
            $scope.isReadonly = true;
            $scope.isChecked = true;
            $scope.isSelected = true;
        }])

注: 不是将属性值设为 true 或 false,而是该属性是否出现。

Angular - 指令_第2张图片
类布尔属性

ng-hrefng-src 等属性虽然不是标准的 HTML 布尔属性,但是由于行为相似,所以 AngularJS 是和布尔属性同等对待的。

  1. ng-href
    url 为动态绑定时,应使用 ng-href 代替 href,AngularJS 会在链接生效后再执行点击行为。
  2. ng-src
    src 地址为动态绑定时,应使用 ng-src 代替 src,AngularJS 会告诉浏览器,在 ng-src 对应的表达式生效之前不要加载图像。
在指令中使用子作用域

ng-appng-controller 是特殊的指令,因为他们会修改嵌套在它们内部的指令的作用域。

  1. ng-app
    任何具有 ng-app 属性的 DOM 元素将会被标记为 $rootScope$rootScope 是作用域链的起始点,任何嵌套在 ng-app 内的指令都会继承它)的起始点。
    注:如果需要在一个页面中放置多个 AngularJS应用,需要手动引导应用。
  2. ng-controller
    在 DOM 元素上放置一个控制器,为嵌套在其中的指令创建一个子作用域,避免将所有操作和模型都定义在 $rootScope 上。
    ng-controller 接收一个必备参数 expression(一个 AngularJS 表达式)。
    以下内置指令具有同样的特性:
  3. ng-include
    使用 ng-include 可以加载、编译并包含外部 HTML 片段到当前应用中。
  4. ng-switch
    ng-switchng-switch-whenon="propertyName" 一起使用,可以在 propertyName 发生变化时渲染不同指令到视图中。

默认显示

满足条件显示

Angular - 指令_第3张图片
  1. ng-view
    ng-view 用来设置将被路由管理和放置在 HTML 中的视图的位置。
  2. ng-if
    ng-if 可以根据表达式的值在 DOM 中生成或移除一个元素。
  3. ng-repeat
    ng-repeat 用来遍历一个集合或为集合中的每个元素生成一个模板实例。
  • $index:遍历索引(0 ~ length - 1)。
  • $first:当元素为遍历的第一个时值为 true
  • $middle:当元素处于第一个和最后一个之间时值为 true
  • $last:当元素为遍历的最后一个时值为 true
  • $even:当 $index 的值为偶数是值为 true
  • $odd:当 $index 的值为奇数是值为 true
.even {
    background: #abcdef;
}
.odd {
    background: #eee;
}
.first {
    background: #ff0;
}
.last {
    background: #f00;
}

{{$index}}

Angular - 指令_第4张图片
  1. ng-init
    ng-init 用来设置指令被调用时的内部作用域的初始状态。
  2. {{ }}
    {{ }} 是 AngularJS 内置的模板语法,在 $scope 和视图之间创建绑定,$scope 变化时,视图就会随之自动更新。
    注: {{ }} 实际上是 ng-bind 的简略形式,但在屏幕可视区内使用 {{ }} 会导致页面加载时未渲染的元素发生闪烁,用 ng-bind 可以避免这个问题。
  3. ng-bind
    {{ }}
  4. ng-cloak
    除了使用 ng-bind 来避免闪烁外,还可以在含有 {{ }} 的元素上使用 ng-cloak 指令。
  5. ng-bind-template
    ng-bind 类似,ng-bind-template 用来在视图中绑定多个表达式。

  1. ng-model
    ng-model 用来将表单控件同包含它们的作用域中的属性进行绑定。
  2. ng-show / ng-hide
    ng-showng-hide 是通过 CSS 控制元素的显隐(ng-if 则是通过添加或移除 dom)。
  3. ng-change
    在表单输入发生变化时触发。需要与 ng-model 一起使用。
  4. ng-form
    ng-form 用来在一个表单内部嵌套另一个表单。普通的 HTML 标签不允许嵌套,但是 ng-form 可以(所以,只有内部所有子表单都合法时,外部表单才合法)。
    下列 CSS 类会根据表单的验证状态自动设置:
  • 表单合法时设置 ng-valid
  • 表单不合法时设置 ng-invalid
  • 表单未进行修改时设置 ng-pristion
  • 表单进行过修改时设置 ng-dirty
input {
    margin-bottom: 10px;
}
input.ng-invalid {
    border: 1px solid red;
}
input.ng-valid {
    border: 1px solid green;
}

    
必填项
angular.module('myApp', [])
    .controller('FormCtrl', function($scope) {
    $scope.fields = [
        {placeholder: '请输入用户名', isRequired: true},
        {placeholder: '请输入密码', isRequired: true},
        {placeholder: '请输入邮箱(选填)', isRequired: false}
    ];
    $scope.submitForm = function() {
        alert("it works!");
    };
});
Angular - 指令_第5张图片
  1. ng-click
    ng-click 用来指定元素被点击是所触发的事件。
  2. ng-select
    ng-select 用来将数据同 HTML 的

    Winner:{{item.name}}

angular.module('directive', [])
        .controller('Directive', Directive);
    Directive.$inject = ['$scope'];
    function Directive ($scope) {
        $scope.list = [
            {
                id: 1,
                name: 'player1'
            }, {
                id: 2,
                name: 'player2'
            }, {
                id: 3,
                name: 'player3'
            }
        ];
    }
  1. ng-submit
    ng-submit 用来将表达式同 onsubmit 时间进行绑定。这个指令会阻止默认行为(发送请求并重新加载页面),但前提是表单不含有 action 属性。
  2. ng-class
    ng-class 可以动态设置元素的类,给要动态添加的类绑定一个表达式,当表达式为 true 时,这个类会被添加,反之会被移除。
  3. ng-attr-(suffix)
    当 AngularJS 编译 DOM 时会查找花括号 {{ some expression }} 内的表达式。这些表达式会被自动注册到 $watch 服务中并更新到 $digest 循环中,成为他的一部分:

{{title}}

有时候浏览器会对属性进行严格限制,如 SVG


    

此时会报错,指出有一个非法属性。这时可以用 ng-attr-(suffix) 解决。


    

  1. ng-style
    ng-style 为 HTML 元素添加 style 属性,且属性值必须是对象。

$scope.style = {
    width: '100px',
    height: '100px',
    background: '#000'
}

自定义指令

定义一个指令
angular.module('directive', [])
    .directive('myDirective', myDirective);

function myDirective () {
    // 一个指令定义对象
    return {
        // 通过设置项定义指令
    }
}

directive() 方法接收两个参数:

  1. name (字符串)
    指令的名字,用来在视图中引用该指令。
  2. factory_function (函数)
    该函数返回一对象,在其中定义这个指令的全部行为。$compile 服务利用这个方法返回的对象,在 DOM 调用指令时来构造指令的行为。
指令的配置项
angular.module('directive', [])
    .directive('myDirective', myDirective);

function myDirective () {
    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 告诉 AngularJS 该指令以何种形式在 DOM 中被声明(默认 A)。
    E - 以元素形式声明

    C - 以类名形式声明


    M - 以注释形式声明
    < !-- directive:my-directive -- >
    A - 以属性形式声明

  • priority (Number)
    priority 可以用来设置指令的优先级,默认 0,通常情况下会忽略该属性,使用默认值(但也有场景需要设置高优先级,如 ng-repeat 的该参数为 1000,所以它总是在其他指令之前被调用;若优先级一直,则先声明先调用)。

  • terminal (Boolean)
    terminal 可以用来阻止当前元素上比自己优先级低的指令。
    例:ngIf 的优先级略高于 ngView, 如果 ngIf 表达式值为 true, 则 ngView 会正常执行,反之,由于 ngView 优先级较低就不会被执行。

  • template (String or Function)
    template 为可选参数,可以为:

    1. 一段 HTML 文本;
    2. 一个可以接受两个参数(tElementtAttrs)的函数,并返回一个代表模板的字符串。tElementtAttrs 中的 t 代表 template
      注:模板字符串中必须只存在一个根 DOM 元素
template: '
template
',

折行时需在末尾加上反斜线,这样才能正确解析多行字符串。

template: '
\ template\

wrap

\
',
  • templateUrl (String or Function)
    templateUrl 为可选参数,可以为:

    1. 一个代表外部 HTML 文件路径的字符串;
    2. 一个可以接受两个参数的函数,参数为 TElementtAttrs,并返回一个外部 HTML 文件路径的字符串。
  • replace (Boolean)
    replace 为可选参数,如果设置这个参数,值必须为 true(默认为 false)。
    若值为 false 则意味着模板会被当做子元素插入到调用此指令的元素内部:

    Angular - 指令_第6张图片

若值为 true 则意味着模板会替换调用此指令的元素:

Angular - 指令_第7张图片

  • scope (Boolean or Object)
    scope 为可选参数,可以设置为 true 或一个对象(默认为 false)。
    若值为 true,会从父作用域继承并创建一个新的作用域对象。
    每个指令被调用时可能会:
    (1). 默认值 false,继承父作用域不创建新作用域(互相影响);
父:{{value}}
Angular - 指令_第8张图片
默认值 `false`

(2). scope: true,创建一个新的继承父作用域的新的独立作用域(互不影响);

父:{{value}}
Angular - 指令_第9张图片
scope: true

(3). scope: {} / {...}
a.{}:创建一个隔离父作用域的新作用域

父:{{value}}
Angular - 指令_第10张图片
scope: {}

b. {...}:可以与父作用域的属性方法进行绑定
绑定的三种形式:
@ (or @attr):绑定字符串
= (or =attr):双向绑定
& (or &attr):绑定方法

选手 {{obj.id}} 的成绩为: {{obj.value}}
Angular - 指令_第11张图片
scope: {...}
  • transclude (Boolean or Object)
    transclude 设置是否将指令内部的元素嵌入到模板中,可选参数,如果设置这个参数,默认为 false
  • controller (String or function)
    controller 为字符串时,会以字符串的值为名字,查找注册在应用中的控制器构造函数,也可以通过匿名构造函数的方式定义一个内联控制器(可以向其中注入任意 AngularJS 服务)。
    (1). $scope:与指令元素相关联的作用域;
    (2). $element:当前指令对应的元素;
    (3). $attrs:由当前元素的属性组成的对象;
    (4). $transclude:嵌入链接函数会与对应的嵌入作用域进行预绑定(transclude 链接函数是实际被执行用来克隆元素和操作 DOM 的函数)。
angular.module('myApp', [])
  .directive('directiveDom', function () {
    return {
      restrivt: 'ECMA',
      controller: function ($scope, $element, $attrs, $transclude) {

      }
    }
  });

注:controller 主要是用来提供可以在指令间复用的行为,link 只能在当前内部指令中定义行为,无法在指令间复用

  • controllerAs (String)
    controllerAs 用来设置控制器别名
  • require (String or Array)
    require 可以将 controller 注入到其值所指定的指令中,并作为当前指令 link 的第四个参数,设置为字符串时,代表另外一个指令的名字。
    require 参数值的修饰前缀:
    (1).?:在当前指令进行搜索(如果没有会传入 null);
    (2).^:在上游指令链中进行搜索;
    (3).?^:可以选择地加载需要的指令并在父指令链中进行搜索;
    (4).无:在自身所提供的控制器中进行搜索(如果没有会抛出一个错误)。
  • compile (Object or Function)
    通常情况下,设置 compile 函数是希望在指令和实时数据被放到 DOM 中之前进行 DOM 操作(编译函数负责对模板 DOM 进行转换)。
    注:compilelink 是互斥的,如果同时设置,则 link 会被忽略。
  • link (Function)
    如果指令中有 require 选项,则第四个参数代表控制器或所依赖的指令的控制器,若 require 选项为一个指令数组,则第四个参数代表由每个指令所对应的控制器所组成的数组(链接函数负责将作用域和 DOM 进行链接)。
    (1). scope:作用域;
    (2). iElement:实例元素,即使用此指令的元素;
    (3). iAttrs:实例属性(可以在所有指令的链接函数间共享);
    (4). controller:指向 require 选项所定义的控制器(可以在所有指令间共享)。

参考资料:
《Angular JS 权威教程》

你可能感兴趣的:(Angular - 指令)