壹 ❀ 引html
贰 ❀ 建立一个简单componentangularjs
<body ng-controller="myCtrl"> <my-name></my-name> <you-name></you-name> </body>
angular.module('myApp',[]) .controller('myCtrl',function () {}) .component('myName',{ template:'<div>个人名字是听风是风</div>' }) .directive('youName',function (){ return{ restrict:'AE', replace:true, template:'<div>你的名字是陌生人</div>' } })
能够看到directive须要在注册名字后紧接回调函数,并在回调函数中返回一个包含directive配置的对象;而component简单不少,component名后面只用紧跟一个包含配置的对象便可,一个彻底的component应该是这样:npm
angular.module('myApp', []) .controller('myCtrl', function () {}) .component('componentName', { template: 'String or Template Function', templateUrl:String, transclude:Boolean, bindings: {}, controllerAs:String, require:String, controller: function () {}, })
属性相比directive简直少了一大半,最直观的就是没了编译函数compile与连接函数link,下面咱们一一介绍相关属性。服务器
叁 ❀ 参数详解函数
1.template /ˈtempleɪt/ 模板ui
component的template用法与directive保持一致,将你须要渲染的DOM结构以字符串的形式拼接好做为template的值便可,好比在文章开头一个简单的例子就展现了template的用法。this
可是有一点与directive不一样,directive要求模板文件结构最外层必须使用一个根元素包裹(无论使用template仍是templateUrl),可是component并无这个要求,好比这样:spa
angular.module('myApp',[]) .controller('myCtrl',function () {}) .component('myName',{ template:'<div>个人名字是听风是风。</div><div>要作一个温柔的人。</div>' })
能够看到在template有两个同级的div元素,我并未用一个根元素包裹这两div也能正常显示,但若是是directive这样作就会报错:3d
.directive('youName',function (){ return{ restrict:'AE', replace:true, template:'<div>个人名字是听风是风。</div><div>要作一个温柔的人。</div>' } })
2.templateUrl 模板路径双向绑定
component的templateUrl用法与directive用法一致,将模板的路径地址做为值赋予给templateUrl便可,好比这样:
angular.module('myApp',[]) .controller('myCtrl',function () {}) .component('myName',{ templateUrl:'../template/myName.html' })
须要注意的是加载模板须要服务器,不然会报错,这里给你们推荐一个本地服务器 live-server,用法很简单,你们能够看看。
3.transclude
在使用component时,若是组件中包含了其它DOM结构或者其它组件,你会发现组件解析后,本来的DOM直接消失不见了,看个例子:
<div ng-controller="myCtrl"> <my-name> <div>要作一个努力的人。</div> </my-name> </div>
angular.module('myApp', []) .controller('myCtrl', function () {}) .component('myName', { template: '<div >我是听风是风</div>' })
在组件my-name中本来还包裹了一个div元素,可是在模板解析后能够看到这个div直接被替换掉了,若是咱们想保留这个div就得使用transclude属性,transclude通常与ng-transclude指令一块儿使用,看个例子:
angular.module('myApp', []) .controller('myCtrl', function () {}) .component('myName', { transclude: true, template: '<div >我是听风是风</div><div ng-transclude><div>' })
HTML结构不变,咱们在组件中新增了 transclude:true,并在模板中新增了一个div元素,并为此div元素添加了ng-transclude指令,再看组件解析后就正常了,你会发现你想保留的div元素成了添加了ng-transclude指令元素的子元素。
若是咱们要使用组件嵌套,这个属性也是必不可少,关于transclude就说到这。
4.controller
每一个组件都拥有本身的controller控制器用于定义组件须要的数据方法等,component的controller值也能够是一个字符串或者一个函数,先说字符串的状况:
angular.module('myApp', []) .controller('myCtrl', function ($scope) { let vm = this; this.name = '时间跳跃'; $scope.age = 26; }) .component('myName', { transclude: true, template: '<div >个人名字是{{$ctrl.name}},我今年{{age}}了。</div>', controller:'myCtrl' })
神奇的是我在component中并未定义一个叫myCtrl的构造器,可是component仍是解析了数据,这是由于当controller值为字符串时就会从应用中查找与字符串同名的构造函数做为本身的控制器函数,很明显父做用域控制器恰好也叫myCtrl,因此这就直接拿来用了。
这么作有个优势就是,component是默认自带隔离做用域的,也就是说父做用域的数据是没法经过继承传递给子组件,若是你组件自身并无其它数据方法,经过这种办法却是能够投机取巧一波。
固然controller咱们通常的写法是后面接一个回调函数,像这样:
angular.module('myApp', []) .controller('myCtrl', function ($scope) {}) .component('myName', { transclude: true, template: '<div >个人名字是{{$ctrl.name}},我今年{{age}}了。</div>', controller: function ($scope){ let vm = this; this.name = '听风是风'; $scope.age = 18; } })
4.controllerAs
咱们知道controller与view通讯有两种方式,一是经过scope,将数据绑在scope上,视图中经过表达式解析便可渲染,二是经过this绑定,这里的controllerAs就是用来设置控制器的别名,controllerAs默认值为$ctrl,在上面的例子中已经有展现,咱们再来看个例子:
angular.module('myApp', []) .controller('myCtrl', function ($scope) {}) .component('myName', { transclude: true, template: '<div >个人名字是{{vm.name}},我今年{{vm.age}}了。</div>', controllerAs: 'vm', controller: function ($scope) { let vm = this; this.name = '听风是风'; this.age = 18; } })
在上面的例子中,咱们将controllerAs的值设置成vm,那么在模板中使用这个值时就是经过vm访问,若是你们对于scope与控制器controller的this有何区别存在疑惑,能够阅读博主这篇文章 angularjs $scope与this的区别,controller as vm有何含义?
4.bindings 父传值给子组件
还记得directive有一个scope属性能够决定directive是否建立隔离做用域,若是scope的值为对象,则表示指令建立隔离做用域,再也不继承父做用域中的属性,父做用域想传值就得依赖绑定策略。
而component的bindings就是对应directive的scope:{}的状况,component默认建立隔离做用域,若是想使用父做用域的数据,就得使用bindings结合绑定策略,咱们来看个例子:
<div ng-controller="myCtrl"> <my-name user-name="name" say-name="sayName"></my-name> </div>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { $scope.name = "听风是风"; $scope.sayName = function () { console.log($scope.name); }; }) .component('myName', { transclude: true, template: '<div >个人名字是{{vm.userName}}。</div><button ng-click="vm.sayName()">点我</button>', controllerAs: 'vm', bindings:{ userName:'<', sayName:'<' } })
在HTML中的组件上,咱们以key-value的形式传值咱们须要在组件中访问的属性和方法,注意key若是是多个单词建议使用 - 拼接,但在bindings中得改成小驼峰形式,这样咱们就能够在模板中直接使用了。
在bindings中咱们能够看到须要传值的数据后面跟了一个<符号,这是绑定策略的规则,<表示单项绑定,即数据传递给组件后,父做用域若是修改了数据,子会同步改变,但若是子修改不会修改父,看个例子:
<div ng-controller="myCtrl"> 我是父做用域:<input type="text" ng-model="name"><br> <my-name user-name="name" say-name="sayName"></my-name> </div>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { $scope.name = "听风是风"; }) .component('myName', { transclude: true, template: '我是组件:<input ng-model="vm.userName">', controllerAs: 'vm', bindings:{ userName:'<', } })
但若是咱们将<改成 = 符号表示双向绑定,无论修改父仍是子,双方都会同步更新,改为=以后是这样:
但须要注意的一点是,若是传递的数据是一个对象,因为浅拷贝的缘故,无论你用 = 仍是<,若是修改了对象的属性,父子都会同步更新。
component的绑定策略不像directive那么复杂,在directive中若是想传递一个字符串给子组件,绑定策略还得使用@,并且在HTML中定义传值还得写成user-name="{{name}}",component总体就简单不少。
可是上面的例子是传递过来后直接给模板在使用,若是我想在组件的controller中使用怎么办呢,若是你尝试在控制器中打印传过来的值,你会发现是拿不到的,这里得借用钩子函数,好比onInit,咱们来看个例子:
angular.module('myApp', []) .controller('myCtrl', function ($scope) { $scope.name = "听风是风"; }) .component('myName', { transclude: true, template: '我是组件:<input ng-model="vm.userName">', controllerAs: 'vm', bindings: { userName: '=', }, controller: function ($scope) { console.log(this.userName);// undefined console.log($scope.userName);// undefined this.$onInit = function () { console.log(this.userName);// 听风是风 console.log($scope.userName);// undefined }; } })
仍是同样的传值,我分别在钩子函数内外打印了this.userName与$scope.userName,首先能够肯定的是只能在钩子函数内访问到传递的值,那为何this能够访问而$scope访问不到呢,由于component传值是绑定在控制器上的,因此只能经过this访问。
关于钩子函数我会单独利用一篇博客介绍,这里先挖坑,另外directive传值是绑定在scope上的,因此不须要$onInit你都能直接经过scope访问。
伍 ❀ 总
那么到这里component用法及属性就介绍完,说到底component就是阉割版的directive,用法上仍是大同小异,directive怎么玩到了component仍是同样,但从建立组件角度来讲,component确实更简单更方便。
若是你要在组件编译阶段或者连接阶段作什么操做,或者说要操做DOM,component就没法知足你的需求,毕竟component未提供编译与连接函数,并且component默认只有使用element建立组件,并不支持属性类名或注释。
聊完了directive指令与component组件,你是否以为这两兄弟看着类似却又有一些不一样,若是你以为让你有一些糊涂,不要紧,下一篇博客咱们从使用角度细致介绍二者的区别。
那么本文到这里就真是结束了,但愿对你又帮助。