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


 壹 ❀ 引

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

 貳 ❀ 區別詳解

  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  YES
terminal(優先權低的組件是否執行)  YES  NO
transclude  YES(默認false)  YES(默認false)

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

1.創建與使用方式不同

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

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

<!-- 指令 -->
<!-- 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.模板使用不同

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

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.父子傳值表現不同

我們知道指令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組件

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM