壹 ❀ 引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
若對於本文介紹的知識點有所疑惑,歡迎留言,我會及時回覆,那麼到這裏本文結束。