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 | NO |
| 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中directive指令与component组件有什么区别?的更多相关文章
- AngularJS中Directive指令系列 - scope属性的使用
文章是转的,我做下补充.原文地址:https://segmentfault.com/a/1190000002773689 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部 ...
- AngularJS中Directive指令系列 - 基本用法
参考: https://docs.angularjs.org/api/ng/service/$compile http://www.zouyesheng.com/angular.html Direct ...
- angularjs学习之六(angularjs中directive指令的一般编程事件绑定 模板使用等)
angular js 中模板的使用.事件绑定以及指令与指令之间的交互 相应教学视频地址(需FQ):v=aG8VD0KvUw4">angularjs教学视频 <!doctype h ...
- AngularJS中Directive指令系列
近段时间在研究Angular中的directive用法,打算写个系列.以官方文档为主.并参考诸多教程.加上自己的思考. 基本概念及用法 scope属性的使用. &, <, =, @ 符 ...
- AngularJS中Directive指令系列 - bindToController属性的使用
默认false.这个属性用来绑定scope的属性直接赋给controller.可以为true或者和scope相同格式的对象. 此外使用此属性,要设置controller的别名,通常通过"co ...
- angularJS中directive父子组件的数据交互
angularJS中directive父子组件的数据交互 1. 使用共享 scope 的时候,可以直接从父 scope 中共享属性.使用隔离 scope 的时候,无法从父 scope 中共享属性.在 ...
- AngularJS中的指令全面解析(转载)
说到AngularJS,我们首先想到的大概也就是双向数据绑定和指令系统了,这两者也是AngularJS中最为吸引人的地方.双向数据绑定呢,感觉没什么好说的,那么今天我们就来简单的讨论下AngularJ ...
- 牛客网Java刷题知识点之什么是JSP的3大常用指令、JSP的6大哪些动作、JSP中include指令和include动作有什么区别
不多说,直接上干货! JSP的3大常用指令 包含指令(Include directive):用来包含文件和合并文件内容到当前的页面. 页面指令(Page directive):用来定义JSP页面中特定 ...
- AngularJS中的指令
欢迎大家讨论与指导 : ) 前言 当AngularJS中的内置指令不能满足我们的需求,或者当我们需要创建一个能够用于多个AngularJS程序的自包含的功能单元时,我们应该创建自定义指令来满足需求. ...
随机推荐
- JS内置对象-Array之forEach()、map()、every()、some()、filter()的用法
简述forEach().map().every().some()和filter()的用法 在文章开头,先问大家一个问题: 在Javascript中,如何处理数组中的每一项数据? 有人可能会说,这还不简 ...
- netty用法总结
/**decoder和encoder,如果不需要解析,就使用系统的 * ch.pipeline().addLast(new StringDecoder()); * ch.pipeline().addL ...
- 《Java基础知识》Java正则表达式
正则表达式定义了字符串的模式. 正则表达式可以用来搜索.编辑或处理文本. 正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别. 正则表达式实例 一个字符串其实就是一个简单的正则表达式,例如 ...
- IPFS学习-IPNS
星际名称系统(IPNS)是一个创建个更新可变的链接到IPFS内容的系统,由于对象在IPFS中是内容寻址的,他们的内容变化将导致地址随之变化.对于多变的事物是有用的.但是很难获取某些内容的最新版本. 在 ...
- 这几天加班熬夜把所有Python库整理了一遍,非常全面!
库名称简介 Chardet 字符编码探测器,可以自动检测文本.网页.xml的编码.colorama 主要用来给文本添加各种颜色,并且非常简单易用.Prettytable 主要用于在终端或浏览器端构建格 ...
- FCC---CSS Flexbox: Use the flex-direction Property to Make a Column
The last two challenges used the flex-direction property set to row. This property can also create a ...
- hadoop集群搭建教程
1. 相关软件准备: VMware-workstation-full-15.0.4-12990004.exe CentOS-7-x86_64-DVD-1810.iso jdk-8u231-linux- ...
- VS2019 开发Django(五)------createsuperuser
导航:VS2019开发Django系列 上篇我们已经把LazyOrders中用到的C#的实体转成了Django中的Entity,并且已经迁移数据库成功,那么,今天继续介绍Django中内置的数据库操作 ...
- MSP430系列单片机特性及应用领域
概述 MSP430系列单片机是德州仪器1996年开始推向市场的一种16位超低功耗的混合信号处理器,给人们留下的最大的亮点是低功耗而且速度快,汇编语言用起来很灵活,寻址方式很多,指令很少,容易上手.主要 ...
- React中refs持久化
根据使用React的版本,选择合适的方法. 字符串模式 :废弃不建议使用 回调函数,React版本 < 16.3 React.createRef() :React版本 >= 16.3 回调 ...