Vue元件應用
Vue的元件是可複用的 Vue 例項,且帶有一個名字 。我們可以在一個通過 new Vue
建立的 Vue 根例項中,把這個元件作為自定義元素來使用。因為元件是可複用的 Vue 例項,所以它們與 new Vue
接收相同的選項,例如 data
、computed
、watch
、methods
以及生命週期鉤子等。僅有的例外是像 el
這樣根例項特有的選項。
一 建立元件
Vue提供了三種不同的方式來定義元件,分別是:全域性元件,私有元件,單檔案元件。接下來就讓我一一道來。
1,全域性元件
註冊全域性元件非常簡單,也是很常用的一種方式。
1 Vue.component('myCom',{ 2 template:'<div><p>我是一個全域性<span>元件</span></p></div>' 3 });
Vue.component()方法需要兩個引數:
第一個,元件名稱;
第二個,例項(初始化)物件,可以包含所有使用new方式建立Vue例項時提供的所有屬性,除了el。
注意:元件的例項物件必須提供一個template屬性,用作該元件的HTML程式碼模板,且在該模板中有且只能有一個根元素。全域性元件的註冊必須在建立Vue例項之前。
小技巧:由於在編寫JS時,一般沒有HTML程式碼提示,建立元件模板程式碼會很不方便,所有可以在HTML檔案中使用<template>元素建立模板,然後在元件的template屬性中使用id選擇器引用該模板。
注意:<template>元素必須在new Vue例項接管的根元素外部。
1 <template id="tem"> 2 <div> 3 <p>我是元件內的p</p> 4 <span>我是元件中的span</span> 5 </div> 6 </template> 7 <!-- 在HTML中 -->
1 Vue.component('myCom',{ 2 template:'#tem' 3 });
4 //在元件中
2,私有元件
全域性建立的元件在所有Vue例項中均可以使用,有時候這並不符合我們的需求。你可以通過以下方式定義Vue例項的私有元件,這些元件只能在該Vue例項根元素內部使用。
1 var vm = new Vue({ 2 el:'#app', 3 components:{ 4 mycom:{ 5 template:'#tem' 6 } 7 } 8 });
通過Vue例項的components屬性可以定義私有元件,該屬性繫結一個物件,物件的屬性名是元件名,屬性值是元件例項物件。
3,單檔案元件
Vue的單檔案元件是一個以.vue為字尾名的檔案。由於HTML和JavaScrip不能識別.vue檔案,所以不能直接使用這種方式的元件,必須配合webpack或vue-cli工具才能正確解析.vue檔案。這裡的重點是Vue單檔案元件,所以有興趣的同學請移步webpack中文網。
1 <tempalte> 2 //HTML模板 3 </template> 4 <script> 5 //JS程式碼 6 </script> 7 <style> 8 //CSS程式碼 9 </style>
.vue檔案的名稱就是元件的名稱,其結構非常簡單、清晰:
<template>標籤是元件的HTML模板;
<script>標籤是邏輯程式碼;
<style>標籤中是樣式程式碼。
二 元件的使用
不管以哪種方式建立Vue元件,我們最終的目的是在HTML頁面中展示出來。本節將詳細介紹Vue元件使用方式。
1,元件標籤
要把我們建立的Vue元件新增到頁面中去,只需要把元件名當做標籤來使用即可。
1 Vue.component('myCom',{ 2 template:"#tem" 3 }); 4 var vm = new Vue({ 5 el:"#app" 6 }); 7 //JS部分
1 <div id="app"> 2 <my-com></my-com> 3 </div> 4 <!-- HTML部分 -->
小技巧:註冊元件時,建議使用全小寫形式命名,因為HTML標籤要求使用小寫字母。如果你一定要遵守小駝峰命名規則,那麼你應該在使用元件時用“-”短橫線把單詞分隔開。
2,元件複用
Vue的元件可以重複使用。
1 <div id="app"> 2 <my-com></my-com> 3 <my-com></my-com> 4 <my-com></my-com> 5 </div>
當然,全域性元件可以在任何地方使用,而私有元件只能在例項接管元素內部使用。
元件不僅可以簡單的重複使用,還可以巢狀。
1 var vm = new Vue({ 2 el:'#app', 3 compontents:{ 4 mycom1:{ 5 template:'<div>元件一 <mycom2></mycom2></div>' 6 }, 7 mycom2:{ 8 template:'<div>元件二</div>' 9 } 10 } 11 });
3,另一種使用方式
1 var mycom = { 2 tempalte:'<div id="app2">hello</div>' 3 }; 4 var vm = new Vue({ 5 el:'#app', 6 render:function(createEl){ 7 return createEl(mycom); 8 } 9 });
使用render方式渲染元件:給Vue例項新增render屬性,該屬性值是一個接收一個方法作為引數的函式。引數用於建立Vue元件,return該元件將替代Vue例項接管的#app元素。最終的表現是:頁面上將不再出現#app的div,取而代之的是#app2的div。
這種方式一般配合單檔案元件使用,如果要渲染多個元件,只需要建立多個Vue例項即可。
三 資料傳遞(通訊)
1,props傳遞資料(父元件 --> 子元件)
通過在子元件繫結props屬性,實現父元件向子元件傳遞資料。props屬性值是一個數組,陣列元素被定義用來接收父元件傳遞來的資料,然後通過v-bind指令指定陣列元素接收哪些資料。子元件通過訪問props陣列元素就可以訪問到父元件傳遞過來的資料了,就如同訪問data裡面的值。
1 <div id="app"> 2 <mycom :fromFatherMsg="toSonMsg"></mycom> 3 </div> 4 <!-- HTML部分 -->
1 Vue.component({ 2 template:"<div>{{fromFatherMsg}}</div>", 3 props:["fromFatherMsg"] 4 }); 5 var vm = new Vue({ 6 el:'#app', 7 data:{ 8 toSonMsg:'這是給子元件的資料' 9 } 10 }); 11 //JS部分
通過上面的例子,我們可以將這個過程簡單的分為三步:
第一步,在子元件上新增一個數組屬性props,在陣列中定義用來接收資料的變數(以字串形式儲存);
第二步,使用子元件時通過v-bind指令,繫結預先定義的接收變數和父元件將要傳遞過來的值;
第三步,在子元件中,如同訪問data中的資料一樣,訪問props陣列元素接收到的資料。
2,$emit傳遞方法(父元件 --> 子元件)
父元件向子元件傳遞方法,是通過自定義事件來實現的。子元件通過例項的$emit()方法呼叫,這裡的事件名將成為$emit()方法的引數。
1 <div id="app"> 2 <mycom @fromFatherFun="toSonFun"></mycom> 3 </div> 4 <!-- HTML部分 -->
1 Vue.component({ 2 template:"<div><button @click="myFun">點選執行來自父元件的方法</button></div>", 3 methods:{ 4 myFun:function(){ 5 this.$emit('fromFatherFun'); 6 } 7 } 8 }); 9 var vm = new Vue({ 10 el:'#app', 11 methods:{ 12 toSonFun(){ 13 console.log( "這是給子元件的方法"); 14 }, 15 }); 16 //JS部分
注意:和傳遞資料一樣,子元件不能直接使用父元件的方法。子元件需要通過例項的$emit()方法間接執行來自父元件的方法。
這一過程也可以分為三步:
第一步,使用子元件時,通過v-on指令自定義一個事件,事件名用來接收父元件傳遞來的方法;
第二步,繫結自定義事件和父元件需要傳遞的方法;
第三步,通過子元件的$emit()方法(通過實參指定需要觸發的自定義事件)觸發父元件的方法執行;
3,子元件丟擲值(子元件 --> 父元件)
子元件在通過$emit()觸發父元件的方法時,可以同時利用$emit()的第二個引數,來向父元件的方法(傳遞給子元件的那個方法)丟擲一個值。父元件的方法需要定義一個形參來接收這個子元件拋來的值。
1 //接上面的例子 2 Vue.component({ 3 template:"<div><button @click="myFun">點選執行來自父元件的方法</button></div>", 4 data(){ 5 return {name:'ren'}; 6 }, 7 methods:{ 8 myFun:function(){ 9 this.$emit('fromFatherFun',this.name); 10 } 11 } 12 }); 13 var vm = new Vue({ 14 el:'#app', 15 data:{ 16 nameFromSon:null 17 } 18 methods:{ 19 toSonFun(data){ 20 this.nameFromSon = data; 21 }, 22 });
子元件丟擲一個值的原理和父元件給子元件傳遞方法原理是一樣的,只不過是不同的用法而已。雖然有點繞,但有用哦。
4,獲取子元件的引用
在使用子元件時,通過繫結ref屬性,父元件可以通過Vue例項的$refs屬性拿到子元件的引用,然後就可以直接訪問子元件的屬性或方法了。
1 <div id="app"> 2 <mycom ref="sonCom"></mycom> 3 <button @click="printMsgFromSon">點選列印子元件的資訊</button> 4 </div> 5 <!-- HTML部分 -->
1 Vue.component('mycom',{ 2 data:function(){return {name:'ren'}} 3 }); 4 5 var vm = new Vue({ 6 el:'#app', 7 methods:{ 8 printMsgFromSon:function(){ 9 console.log(this.$refs.sonCom.name); 10 } 11 } 12 }); 13 //JS部分
小技巧:ref屬性不僅可以用在元件上,也可以用在其他標準HTML標籤上,這樣Vue例項就可以獲取到原生的DOM物件了。
注意:即使子元件是Vue例項的私有元件,例項也不能直接使用元件的相關資料,還是需要通過$refs等屬性來間接訪問。
四 其他事項
1,單獨的data
經過上面的學習,你可能已經發現了一個問題:元件中的data屬性是一個函式返回的物件。
1 Vue.component("mycom",{ 2 template:"", 3 data(){ 4 return { //some code }; 5 } 6 }); 7 //這是ES6的寫法,等同於data:function(){return {some code};}
由於data屬性繫結的是一個物件,而物件是一個引用型別,為了保證為每個元件維護一份獨立的資料,元件的data屬性必須是一個函式。
2,插槽<slot>
當你讀到這裡時,你可能會有一個疑問:既然我們可以用標籤形式使用Vue元件,那麼是否可以在開始標籤和結束標籤之間填些內容呢?如果可以的話,該如何做呢?Vue的答案是肯定的。
首先請看下面的例子:
1 <div id="app"> 2 <com>我是插槽內容</com> 3 </div> 4 <!-- HTML部分 -->
1 Vue.compenent('com',{ 2 template:'<div><p>我是元件</p><slot>我是預設值<slot></div>' 3 }); 4 var vm = new Vue({ 5 el:'#app' 6 }); 7 //JS部分
"我是插槽內容"將替換com元件中<slot>元素。
注意:如果在使用子元件時沒有提供插槽值,那麼<slot>元素中的預設值將會生效,前提是你已經定義了這些值。
上面的例子中,元件最終渲染的HTML結構如下:
1 <div> 2 <p>我是元件</p> 3 我是插槽內容 4 </div>
注意:插槽的內容不僅可以是文字內容,還可以是HTML程式碼,甚至另一個元件。
如果你需要在一個元件中定義多個插槽,那麼你應該需要用到<slot>元素的name屬性,來指定每個插槽應該擁有怎麼樣的模板。
1 <div> 2 <com> 3 <template v-slot:"header"> 4 <!-- 單獨的HTML模板 --> 5 </template> 6 <div><p>我是預設的模板</p></div> 7 <template v-slot:"footer"> 8 <!-- 單獨的HTML模板 --> 9 </template> 10 </com> 11 </div> 12 <!-- HTML部分 -->
1 Vue.component('com',{ 2 tempalte:'<div><slot name="header"></slot><slot></slot><slot name="footer"></slot></div>' 3 }); 4 var vm = new Vue({ 5 el:'#app' 6 });
具名的插槽需要在使用元件時,用<template>元素單獨定義模板,並通過v-slot指令以引數的形式指定:“我是xxx插槽的模板”。
其他所有沒有包裹在<template>元素內的模板,將自動歸為匿名的<slot>元素下面。
3,特殊的巢狀元素
有些 HTML 元素,諸如 <ul>
、<ol>
、<table>
和 <select>
,對於哪些元素可以出現在其內部是有嚴格限制的。而有些元素,諸如 <li>
、<tr>
和 <option>
,只能出現在其它某些特定的元素內部。要怎樣才能在這些元素中正確的渲染元件呢?幸好,Vue提供了is特性:
1 <table> 2 <tr is="mycom"></tr> 3 </table>
注意:如果你使用字串定義元件模板(例如:template: '...'
)、或者單檔案元件(.vue)、或者<script>標籤(<script type="text/x-template">),那麼你完全可以忽略掉這個限制。
&n