angularjs中directive指令與component組件有什麼區別?

 壹 ❀ 引html

我在前面花了兩篇博客分別系統化介紹了angularjs中的directive指令與component組件,固然directive也能實現組件這點毋庸置疑。在瞭解完二者後,即使咱們知道component就像刪減版的directive,用法上大同小異,但二者在使用角度仍然存在很多差別,那麼本文將詳細對比二者,加深你們的認知,那麼本文開始。angularjs

 貳 ❀ 區別詳解數組

  Directive Component
bindings(用於父傳值子)  NO  YES(綁定至控制器)
bindToController  YES  NO
compile function(編譯函數)  YES  NO
controller  YES  YES
controllerAs  YES(默認flase)  YES(默認$ctrl)
link functions(連接函數)  YSE  NO
multiElement  YES  NO
priority(組件優先權)  YES  NO
replace  YES  NO
require  YES  YES
restrict  YES  NO(僅支持元素)
scope  YES(綁定至scope)  NO(做用域老是隔離)
template  YES  YES
templateNamespace  YES  NO
templateUrl  YES  NO
terminal(優先權低的組件是否執行)  YES  NO
transclude  YES(默認false)  YES(默認false)

這是一份包含了指令directive與組件component全屬性的表格,誰有誰沒有已標註,至於具體用法可閱讀博主先前完成的兩篇博客。如今來講說二者表現不一樣:函數

1.建立與使用方式不一樣ui

在建立上,directive在指令名後是一個回調函數,函數內返回一個包含指令配置的對象,而component在組件名後緊接一個包含組件配置的對象。this

在使用上,directive支持EMAC,即元素註釋屬性與類名,而component僅支持元素,所以component沒有restrict,terminal,replace此類屬性。spa

<!-- 指令 -->
<!-- directive:directive-name -->
<directive-name></directive-name>
<div directive-name></div>
<div class="directive-name"></div>

<!-- 組件 -->
<component-name></component-name>
angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {})
    .directive('directiveName', function () {
        return {
            //定義屬性配置
        }
    })
    .component('componentName', {
        //定義屬性配置
    });

2.模板使用不一樣rest

指令directive在使用模板,不論是template或者templateUrl,都要求模板代碼用一個根元素進行包裹,但component並無這個要求。code

angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {})
    .directive('directiveName', function () {
        return {
            template: '<span>1</span><span>2<span>', //錯誤
            template: '<div><span>1</span><span>2<span></div>' //正確
        }
    })
    .component('componentName', {
        //定義屬性配置
        template: '<span>1</span><span>2<span>', //不會報錯
    });

3.父子傳值表現不一樣component

咱們知道指令directivescope傳值directive綁在scope上,component綁在this上,因此component要使用鉤子函數。固然directive可使用bindTocontroller讓傳值也綁定在this上。

咱們知道component自帶隔離做用域,而directive是否隔離由scope屬性決定,false不建立做用域,true建立做用域但不隔離,{}建立隔離做用域。

當擁有隔離做用域時,父子互不相關,因此子沒法繼承父做用域中的任何數據,component得使用bindings傳值,而directive得使用scope:{}傳值:

<div ng-controller="myCtrl as vm">
    <echo1 name="name" age="vm.age"></echo1>
    <echo2 name="name" age="vm.age"></echo2>
</div>
angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {
        $scope.name = '聽風是風';
        this.age = 26;
    })
    .directive('echo1', function () {
        return {
            restrict: 'AE',
            replace: true,
            scope: {
                name: '<',
                age: '<'
            },
            template: '<div>{{name}}{{age}}</div>',
            controller:function($scope) {
                console.log($scope,this)
            }
        }
    })
    .component('echo2', {
        bindings: {
            name: '<',
            age: '<'
        },
        template: '<div>{{$ctrl.name}}{{$ctrl.age}}</div>',
        controller:function($scope) {
            console.log($scope,this);
        }
    });

在這個例子中,咱們在父級控制器中分別在scope以及this上綁定了兩條數據,並分別傳遞給指令echo1與組件echo2,能夠看到在二者的模板中使用是有差別的,指令使用傳遞過來的數據更像$scope的寫法,而組件更像構造器。

這是由於directive傳值默認是綁定在scope上的,而component傳值默認綁定在控制器上,咱們能夠分別打印二者的scope與this,首先是directive:

能夠看到數據傳遞過來是直接綁定在scope中的,因此用起來與綁在$scope上同樣,再來看看component:

能夠看到傳遞過來的數據不是綁定在scope上,而是組件的控制器上,因爲咱們沒有設置controllerAs,因此這裏默承認以經過$ctrl訪問。

別忘了directive有一個bindToController屬性,做用就是將傳遞過來的值綁定在控制器上,咱們修改代碼,爲directive添加此bindToController:true,再次輸出能夠看到scope與this發生了變化。

    .directive('echo1', function () {
        return {
            restrict: 'AE',
            replace: true,
            scope: {
                name: '<',
                age: '<'
            },
            bindToController: true,
            controllerAs: 'ctrl',
            template: '<div>{{ctrl.name}}{{ctrl.age}}</div>',
            controller: function ($scope) {
                console.log($scope, this)
            }
        }
    })

或許你想問能綁定在scope上幹嗎要綁定在控制器上呢?別忘了directive與component都有一個require屬性,經過此屬性咱們能注入其它組價或指令的控制器,也就是說你能用其它指令中定義的屬性方法,前提是這些屬性方法得綁定在this上,來看個例子:

<div ng-controller="myCtrl as vm">
    <echo1>
        <echo2></echo2>
    </echo1>
</div>
angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {})
    .directive('echo1', function () {
        return {
            restrict: 'AE',
            replace: true,
            controller: function ($scope) {
                $scope.gender = 'male';
                this.name = '聽風是風';
                this.sayName = function(){
                    console.log(this.name);
                }
            }
        }
    })
    .component('echo2', {
        template: '<div><button ng-click="$ctrl.echoCtrl.sayName()">點我</button></div>',
        require:{
            echoCtrl:'?^echo1'
        },
        controller: function ($scope) {
            this.$onInit = function () {
                console.log(this.echoCtrl);
            }
        }
    });

我在指令echo1的controller中分別在scope以及this上綁定了一些屬性,而後在組件echo2中經過require注入echo1的控制器,能夠看到咱們能經過此作法複用已經定義過的屬性方法。同時咱們打印注入的控制器,能夠看到只有綁定在echo1 this上的屬性,scope上的屬性並無傳遞過來。

4.component的controller中通常結合鉤子函數使用,directive不須要

不論是經過scope/bindings傳遞父做用域數據過來,仍是require注入其它指令組件控制器上的屬性方法,在模板上直接使用都是沒問題的,只是一個在scope上一個在控制器上的區別,前面也有例子展現。

但若是咱們要在directive和component的controller中操做傳遞過來的數據component得使用鉤子函數中才能獲取到,不然就是undefined,看個例子:

<div ng-controller="myCtrl">
    <echo1 person="person"></echo1>
    <echo2 person="person"></echo2>
</div>
angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {
        $scope.person = {
            name: '聽風是風',
            age: '26'
        }
    })
    .directive('echo1', function () {
        return {
            restrict: 'AE',
            replace: true,
            scope: {
                person: '<',
            },
            template: '<div>{{name}}</div>',
            controller: function ($scope) {
                //傳遞過來的person綁定在scope上
                $scope.name = $scope.person.name;
            }
        }
    })
    .component('echo2', {
        bindings: {
            person: '<',
        },
        template: '<div>{{name}}</div>',
        controller: function ($scope) {
            //只有在鉤子函數中才能獲取到
            this.$onInit = function (){
                //傳遞過來的person綁定在控制器上
                $scope.name = this.person.name
            }
        }
    });

這個例子中咱們傳遞過來的是一個對象,可是咱們只須要在視圖上渲染對象中的一條屬性,因此在controller中作了一次數據加工。directive直接加工沒問題,可是component必須在鉤子函數中才能取到this.person對象,你們能夠嘗試註釋掉外面的$onInit方法看看區別,這點在使用component的controller處理傳遞過來的數據必定得注意。

5.require使用不一樣

前面已經提到directive與component都能使用require注入其它指令組件的控制器,以達到使用控制器中的數據,不過directive與component在require使用上有一點點區別,看個例子:

<div ng-controller="myCtrl">
    <echo>
        <echo1></echo1>
        <echo2></echo2>
    </echo>
</div>
angular.module('myApp', [])
    .controller('myCtrl', function ($scope) {})
    .directive('echo', function () {
        return {
            restrict: 'AE',
            replace: true,
            controller: function ($scope) {
                this.name = '聽風是風';
            }
        }
    })
    .directive('echo1', function () {
        return {
            restrict: 'AE',
            replace: true,
            require: '?^echo',
            template: '<div>{{name}}</div>',
            link: function (scope, ele, attrs, ctrls) {
                console.log(ctrls);
                scope.name = ctrls.name;
            }
        }
    })
    .component('echo2', {
        require: {
            echoCtrl: '?^echo'
        },
        template: '<div>{{name}}</div>',
        controller: function ($scope) {
            //只有在鉤子函數中才能獲取到
            this.$onInit = function () {
                console.log(this.echoCtrl);
                $scope.name = this.echoCtrl.name;
            }
        }
    });

 

在directive中require的值是一個字符串或者一個數組(注入多個時),而且注入的指令/組件控制器將成爲link函數的第四個參數,注意是link函數不是controller。

而component的require值一直是個對象,被注入的指令/組件的控制器須要做爲自定義key的value,在controller中經過this.key訪問,注意,使用一樣須要鉤子函數。

 叄 ❀ 使用抉擇

咱們在上文中介紹了directive與component使用時存在的部分差別,那麼實際開發中該如何抉擇呢,其實在angular官網就已經給出了答案。

在AngularJS中,組件是一種特殊的指令,它使用更簡單的配置,在屬性默認值和屬性配置實用角度上component有更大的優點,例如require key-value形式相比directive的數組更便於使用,controllerAs自帶了默認值等。

固然directive也有component沒法取代的一面,當咱們須要在編譯和預連接函數中執行操做時,或者同一元素擁有多個指令須要定義優先級時,directive會比component更強大,沒有誰好誰壞,只是根據需求來決定。

 肆 ❀ 總

那麼到這裏,關於directive與component使用區別介紹完畢了,若是你們對於directive與component使用有疑惑,能夠閱讀博主這兩篇文章:

angularjs 一篇文章看懂自定義指令directive

一篇文章看懂angularjs component組件

若對於本文介紹的知識點有所疑惑,歡迎留言,我會及時回覆,那麼到這裏本文結束。

相關文章
相關標籤/搜索