Home  >  Article  >  Web Front-end  >  An in-depth analysis of the usage of Directive in Angular

An in-depth analysis of the usage of Directive in Angular

青灯夜游
青灯夜游forward
2021-04-13 10:45:362367browse

This article will give you a detailed introduction to Angular Directive and understand its usage. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

An in-depth analysis of the usage of Directive in Angular

Angular Directive Learning

Learning purpose: To better understand how to use ng directive.

Directive may be a more complicated thing in AngularJS. Generally we understand it as an instruction. AngularJS comes with many preset instructions, such as ng-app, ng-controller, etc. You can find a characteristic. The instructions that come with AngularJS all start with ng-.

So, what exactly is Directive? My personal understanding is this: encapsulate a piece of HTML and JS together to form a reusable independent entity with specific functions. Let's explain the general usage of Directive in detail.

Common definition format and parameter description of AnguarJS directive

Look at the following code:

var myDirective = angular.module('directives', []);

myDirective.directive('directiveName', function($inject) {
    return {
        template: '<div></div>',
        replace: false,
        transclude: true,
        restrict: 'E',
        scope: {},
        controller: function($scope, $element) {

        },
        complie: function(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {

                },
                post: function postLink(scope, iElement, iAttrs, controller) {

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

        }
    };
});
  • Here an object is directly returned, and the object includes comparison Multiple attributes, these attributes are definitions of custom directives. The detailed meaning will be explained below.
  • return object parameter description
return {
    name: '',
    priority: 0,
    terminal: true,
    scope: {},
    controller: fn,
    require: fn,
    restrict: '',
    template: '',
    templateUrl: '',
    replace: '',
    transclude: true,
    compile: fn,
    link: fn
}

Related tutorial recommendations: "angular tutorial"

As shown above, there will be Many attributes, this line of attributes are used to define directives.

Let’s explain their functions one by one.

  • name

    • represents the name of the current scope. Generally, the default value is used when declaring, and there is no need to manually set this property.
  • priority

    • Priority. When multiple directives are defined on the same DOM element, it is sometimes necessary to specify their execution order. This attribute is used for sorting before the directive's compile function is called. If the priorities are the same, the execution order is uncertain (according to experience, the one with higher priority is executed first, and if the priority is the same, it is bound first and then executed).
  • teminal

    • The last group. If set to true, it means that the current priority will become the last group of directives to be executed, that is, directives with a lower priority than this directive will not be executed. The same priority will still be executed, but the order is uncertain.
  • scope

    • true
      • will create a directive for this directive new scope. If there are multiple directives in the same element that require a new scope, it will still only create one scope. The new scoping rules do not apply to root templates, because root templates tend to get a new scope.
    • {}
      • will create a new, independent scope. The difference between this scope and the general scope is that it does not inherit through prototype of the parent scope. This is helpful for creating reusable components and can effectively prevent the data of the parent scope from being read or modified. This independent scope will create a hash set with a set of local scope properties derived from the parent scope. These local scope properties are helpful for templates to create aliases for values. The definition of a local is a hash mapping of a set of local scope properties to its source.
  • controller

    • controller constructor. The controller will be initialized before the pre-linking step and allow other directives to be shared through the require with the specified name. This will allow directives to communicate with each other and enhance each other's behavior. The controller injects the following local objects by default:
      • $scope The scope combined with the current element
      • $element The current element
      • $attrs The attribute object of the current element
      • $transclude A transposed linking function pre-bound to the current scope
  • require

    • Request another controller and pass it into the linking function of the current directive. require needs to pass in the name of a directive controller. If the controller corresponding to this name cannot be found, an error will be thrown. The name can be prefixed with the following:
      • ? Do not throw an exception. This will make this dependency optional
      • ^ Allows looking up the controller of the parent element
  • restrict

    • A string that is a subset of EACM, which restricts the directive to the specified declaration method. If omitted, the directive will only allow declarations through attributes
      • E Element name:
      • A Attribute name:
      • C Class name:
      • M Comments:
  • template

    • If replace is true, the template content will be replaced with the current html element, and transfer the attributes and classes of the original element together; if replace is false, the template element will be treated as a child element of the current element.
  • templateUrl

    • 与template基本一致,但模版通过指定的url进行加载。因为模版加载是异步的,所有compilation、linking都会暂停,等待加载完毕后再执行。
  • replace

    • 如果设置为true,那么模版将会替换当前元素,而不是作为子元素添加到当前元素中。(为true时,模版必须有一个根节点)
  • transclude

    • 编译元素的内容,使它能够被directive使用。需要在模版中配合ngTransclude使用。transclusion的有点是linking function能够得到一个预先与当前scope绑定的transclusion function。一般地,建立一个widget,创建独立scope,transclusion不是子级的,而是独立scope的兄弟级。这将使得widget拥有私有的状态,transclusion会被绑定到父级scope中。(上面那段话没看懂。但实际实验中,如果通过调用myDirective,而transclude设置为true或者字符串且template中包含的时候,将会将的编译结果插入到sometag的内容中。如果any的内容没有被标签包裹,那么结果sometag中将会多了一个span。如果本来有其他东西包裹的话,将维持原状。但如果transclude设置为’element’的话,any的整体内容会出现在sometag中,且被p包裹)
      • true/false 转换这个directive的内容。(这个感觉上,是直接将内容编译后搬入指定地方)
      • ‘element’ 转换整个元素,包括其他优先级较低的directive。(像将整体内容编译后,当作一个整体(外面再包裹p),插入到指定地方)
  • compile

    • 这里是compile function,将在下面实例详细说明
  • link

    • 这里是link function ,将在下面实例详细讲解。这个属性仅仅是在compile属性没有定义的情况下使用。

关于scope

这里关于directive的scope为一个object时,有更多的内容非常有必要说明一下。看下面的代码:

scope: {
    name: '=',
    age: '=',
    sex: '@',
    say: '&'
}

这个scope中关于各种属性的配置出现了一些奇怪的前缀符号,有=,@,&,那么这些符号具体的含义是什么呢?再看下面的代码:

  • html
<div my-directive name="myName" age="myAge" sex="male" say="say()"></div>复制代码
  • javascript
function Controller($scope) {
    $scope.name = 'Pajjket';
    $scope.age = 99;
    $scope.sex = '我是男的';
    $scope.say = function() {
        alert('Hello,我是弹出消息');
    };
}
可以看出,几种修饰前缀符的大概含义:
  • =: 指令中的属性取值为Controller中对应$scope上属性的取值
  • @: 指令中的取值为html中的字面量/直接量
  • &: 指令中的取值为Controller中对应$scope上的属性,但是这个属性必须为一个函数回调 下面是更加官方的解释:
  • =或者=expression/attr

在本地scope属性与parent scope属性之间设置双向的绑定。如果没有指定attr名称,那么本地名称将与属性名称一致。

  • 例如: 中,widget定义的scope为:{localModel: '=myAttr'},那么widget scope property中的localName将会映射父scope的parentModel。如果parentModel发生任何改变,localModel也会发生改变,反之亦然。即双向绑定。

  • @或者@attr 建立一个local scope property到DOM属性的绑定。因为属性值总是String类型,所以这个值总返回一个字符串。如果没有通过@attr指定属性名称,那么本地名称将与DOM属性的名称一致。 例如: ,widget的scope定义为:{localName: '@myAttr'}。那么,widget scope property的localName会映射出"hello "转换后的真实值。当name属性值发生改变后,widget scope的localName属性也会相应的改变(仅仅是单向,与上面的=不同)。那么属性是在父scope读取的(不是从组件的scope读取的)

  • &或者&attr 提供一个在父scope上下文中执行一个表达式的途径。如果没有指定attr的名称,那么local name将与属性名一致。

    • 例如:

68c72eacde80dbb19dac8db1a79aac0a,widget的scope定义为:{localFn:’increment()’},那么isolate scope property localFn会指向一个包裹着increment()表达式的function。 一般来说,我们希望通过一个表达式,将数据从isolate scope传到parent scope中。这可以通过传送一个本地变量键值的映射到表达式的wrapper函数中来完成。例如,如果表达式是increment(amount),那么我们可以通过localFn({amount:22})的方式调用localFn以指定amount的值。

directive 实例讲解

下面的示例都围绕着上面所作的参数说明而展开的。

  • directive声明实例
// 自定义directive
var myDirective = angular.modeule('directives', []);

myDirective.directive('myTest', function() {
    return {
        restrict: 'EMAC',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        template: '<div><h4>Weather for {{ngModel}}</h4</div>'
    };
});

// 定义controller
var myControllers = angular.module('controllers', []);
myControllers.controller('testController', [
    '$scope',
    function($scope) {
        $scope.name = 'this is directive1';
    }
]);


var app = angular.module('testApp', [
    'directives',
    'controllers'
]);

<body ng-app="testApp">
    <div ng-controller="testController">
        <input type="text" ng-model="city" placeholder="Enter a city" />
        <my-test ng-model="city" ></my-test>
        <span my-test="exp" ng-model="city"></span>
        <span ng-model="city"></span>
    </div>
</body>

template与templateUrl的区别和联系

templateUrl其实根template功能是一样的,只不过templateUrl加载一个html文件,上例中,我们也能发现问题,template后面根的是html的标签,如果标签很多呢,那就比较不爽了。可以将上例中的,template改一下。

myDirective.directive('myTest', function() {
    return {
        restrict: 'EMAC',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        templateUrl:'../partials/tem1.html'   //tem1.html中的内容就是上例中template的内容。
    }
});

scope重定义

//directives.js中定义myAttr
myDirectives.directive('myAttr', function() {
    return {
        restrict: 'E',
        scope: {
            customerInfo: '=info'
        },
        template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
                  'Name: {{vojta.name}} Address: {{vojta.address}}'
    };
});

//controller.js中定义attrtest
myControllers.controller('attrtest',['$scope',
    function($scope) {
        $scope.naomi = {
            name: 'Naomi',
            address: '1600 Amphitheatre'
        };
        $scope.vojta = {
            name: 'Vojta',
            address: '3456 Somewhere Else'
        };
    }
]);

// html中
<body ng-app="testApp">
    <div ng-controller="attrtest">
        <my-attr info="naomi"></my-attr>
    </div>
</body>

其运行结果如下:

Name: Naomi Address: 1600 Amphitheatre      //有值,因为customerInfo定义过的
Name: Address:                              //没值 ,因为scope重定义后,vojta是没有定义的

我们将上面的directive简单的改一下,

myDirectives.directive('myAttr', function() {
    return {
        restrict: 'E',
        template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
                  'Name: {{vojta.name}} Address: {{vojta.address}}'
    };
});
  • 运行结果如下:
Name: Address:
Name: Vojta Address: 3456 Somewhere Else

因为此时的directive没有定义独立的scope,customerInfo是undefined,所以结果正好与上面相反。

transclude的使用

  • transclude的用法,有点像jquery里面的$().html()功能
myDirective.directive('myEvent', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            'close': '$onClick'      //根html中的on-click="hideDialog()"有关联关系
        },
        templateUrl: '../partials/event_part.html'
    };
});

myController.controller('eventTest', [
    '$scope',
    '$timeout',
    function($scope, $timeout) {
        $scope.name = 'Tobias';
        $scope.hideDialog = function() {
            $scope.dialogIsHidden = true;
            $timeout(function() {
                $scope.dialogIsHidden = false;
            }, 2000);
        };
    }
]);
<body ng-app="phonecatApp">
    <div ng-controller="eventtest">
        <my-event ng-hide="dialogIsHidden" on-click="hideDialog()">
            Check out the contents, {{name}}!
        </my-event>
    </div>
</body>

<!--event_part.html -->
<div>
    <a href ng-click="close()">×</a>
    <div ng-transclude></div>
</div>
  • 说明:这段html最终的结构应该如下所示:
<body ng-app="phonecatApp">
    <div ng-controller="eventtest">
        <div ng-hide="dialogIsHidden" on-click="hideDialog()">
            <span>Check out the contents, {{name}}!</span>
        </div>
    </div>
</body>
  • 将原来的html元素中的元素Check out the contents, !插入到模版的中,还会另外附加一个标签。controllerlinkcompile之间的关系
myDirective.directive('exampleDirective', function() {
    return {
        restrict: 'E',
        template: '<p>Hello {{number}}!</p>',
        controller: function($scope, $element){
            $scope.number = $scope.number + "22222 ";
        },
        link: function(scope, el, attr) {
            scope.number = scope.number + "33333 ";
        },
        compile: function(element, attributes) {
            return {
                pre: function preLink(scope, element, attributes) {
                    scope.number = scope.number + "44444 ";
                },
                post: function postLink(scope, element, attributes) {
                    scope.number = scope.number + "55555 ";
                }
            };
        }
    }
});

//controller.js添加
myController.controller('directive2',[
    '$scope',
    function($scope) {
        $scope.number = '1111 ';
    }
]);

//html
<body ng-app="testApp">
    <div ng-controller="directive2">
        <example-directive></example-directive>
    </div>
</body>
  • 上面小例子的运行结果如下:
Hello 1111 22222 44444 5555 !

由结果可以看出来,controller先运行,compile后运行,link不运行。 我们现在将compile属性注释掉后,得到的运行结果如下:Hello 1111 22222 33333 !

由结果可以看出来,controller先运行,link后运行,link和compile不兼容。一般地,compile比link的优先级要高。

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of An in-depth analysis of the usage of Directive in Angular. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete