1. 程式人生 > >Vue元件應用

Vue元件應用

  Vue的元件是可複用的 Vue 例項,且帶有一個名字 。我們可以在一個通過 new Vue 建立的 Vue 根例項中,把這個元件作為自定義元素來使用。因為元件是可複用的 Vue 例項,所以它們與 new Vue 接收相同的選項,例如 datacomputedwatchmethods 以及生命週期鉤子等。僅有的例外是像 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