壹 ❀ 引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組件,你是否以爲這兩兄弟看着類似卻又有一些不一樣,若是你以爲讓你有一些糊塗,不要緊,下一篇博客咱們從使用角度細緻介紹二者的區別。
那麼本文到這裏就真是結束了,但願對你又幫助。