壹 ❀ 引

我在前面花了两篇博客分别系统化介绍了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 component组件

若对于本文介绍的知识点有所疑惑,欢迎留言,我会及时回复,那么到这里本文结束。

angularjs中directive指令与component组件有什么区别?的更多相关文章

  1. AngularJS中Directive指令系列 - scope属性的使用

    文章是转的,我做下补充.原文地址:https://segmentfault.com/a/1190000002773689 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部 ...

  2. AngularJS中Directive指令系列 - 基本用法

    参考: https://docs.angularjs.org/api/ng/service/$compile http://www.zouyesheng.com/angular.html Direct ...

  3. angularjs学习之六(angularjs中directive指令的一般编程事件绑定 模板使用等)

    angular js 中模板的使用.事件绑定以及指令与指令之间的交互 相应教学视频地址(需FQ):v=aG8VD0KvUw4">angularjs教学视频 <!doctype h ...

  4. AngularJS中Directive指令系列

    近段时间在研究Angular中的directive用法,打算写个系列.以官方文档为主.并参考诸多教程.加上自己的思考. 基本概念及用法 scope属性的使用.  &, <, =, @ 符 ...

  5. AngularJS中Directive指令系列 - bindToController属性的使用

    默认false.这个属性用来绑定scope的属性直接赋给controller.可以为true或者和scope相同格式的对象. 此外使用此属性,要设置controller的别名,通常通过"co ...

  6. angularJS中directive父子组件的数据交互

    angularJS中directive父子组件的数据交互 1. 使用共享 scope 的时候,可以直接从父 scope 中共享属性.使用隔离 scope 的时候,无法从父 scope 中共享属性.在 ...

  7. AngularJS中的指令全面解析(转载)

    说到AngularJS,我们首先想到的大概也就是双向数据绑定和指令系统了,这两者也是AngularJS中最为吸引人的地方.双向数据绑定呢,感觉没什么好说的,那么今天我们就来简单的讨论下AngularJ ...

  8. 牛客网Java刷题知识点之什么是JSP的3大常用指令、JSP的6大哪些动作、JSP中include指令和include动作有什么区别

    不多说,直接上干货! JSP的3大常用指令 包含指令(Include directive):用来包含文件和合并文件内容到当前的页面. 页面指令(Page directive):用来定义JSP页面中特定 ...

  9. AngularJS中的指令

    欢迎大家讨论与指导 : )  前言 当AngularJS中的内置指令不能满足我们的需求,或者当我们需要创建一个能够用于多个AngularJS程序的自包含的功能单元时,我们应该创建自定义指令来满足需求. ...

随机推荐

  1. JS内置对象-Array之forEach()、map()、every()、some()、filter()的用法

    简述forEach().map().every().some()和filter()的用法 在文章开头,先问大家一个问题: 在Javascript中,如何处理数组中的每一项数据? 有人可能会说,这还不简 ...

  2. netty用法总结

    /**decoder和encoder,如果不需要解析,就使用系统的 * ch.pipeline().addLast(new StringDecoder()); * ch.pipeline().addL ...

  3. 《Java基础知识》Java正则表达式

    正则表达式定义了字符串的模式. 正则表达式可以用来搜索.编辑或处理文本. 正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别. 正则表达式实例 一个字符串其实就是一个简单的正则表达式,例如  ...

  4. IPFS学习-IPNS

    星际名称系统(IPNS)是一个创建个更新可变的链接到IPFS内容的系统,由于对象在IPFS中是内容寻址的,他们的内容变化将导致地址随之变化.对于多变的事物是有用的.但是很难获取某些内容的最新版本. 在 ...

  5. 这几天加班熬夜把所有Python库整理了一遍,非常全面!

    库名称简介 Chardet 字符编码探测器,可以自动检测文本.网页.xml的编码.colorama 主要用来给文本添加各种颜色,并且非常简单易用.Prettytable 主要用于在终端或浏览器端构建格 ...

  6. 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 ...

  7. hadoop集群搭建教程

    1. 相关软件准备: VMware-workstation-full-15.0.4-12990004.exe CentOS-7-x86_64-DVD-1810.iso jdk-8u231-linux- ...

  8. VS2019 开发Django(五)------createsuperuser

    导航:VS2019开发Django系列 上篇我们已经把LazyOrders中用到的C#的实体转成了Django中的Entity,并且已经迁移数据库成功,那么,今天继续介绍Django中内置的数据库操作 ...

  9. MSP430系列单片机特性及应用领域

    概述 MSP430系列单片机是德州仪器1996年开始推向市场的一种16位超低功耗的混合信号处理器,给人们留下的最大的亮点是低功耗而且速度快,汇编语言用起来很灵活,寻址方式很多,指令很少,容易上手.主要 ...

  10. React中refs持久化

    根据使用React的版本,选择合适的方法. 字符串模式 :废弃不建议使用 回调函数,React版本 < 16.3 React.createRef() :React版本 >= 16.3 回调 ...