Vue組件詳解

使用組件的原因: 提高代碼可復用性

組件的使用方法

  1. 全局注冊
HTML:
<div id="app" v-cloak>    
    <my-component></my-component>  
</div>
JS:
Vue.component('myComponent',{    
    template: '<div>我是一個組件</div>'  
})  
var app = new Vue({    
    el: '#app'  
})
優(yōu)點:所有的Vue實例都可以用 
缺點:權限太大,容錯率降低
  1. 局部注冊
<div id="app" v-cloak>    
    <my-component></my-component>  
</div>
var app = new Vue({    
    el: '#app',    
    components:{      
        'myComponent':{    
            template: '<div>我是一個組件</div>'      
        }    
    }  
})

3. vue組件的模板在某些情況下會受到html標簽的限制,比如<table>中只能含有<tr><td> ,

這些元素,所以直接在table中使用組件是無效的,此時可以使用is屬性來掛載組件

<table>          
    <tbody is="my-component"></tbody>        
</table>

組件使用的技巧

1. 推薦使用小寫字母加-進行命名(必須)

2. template中的內容必須被一個DOM元素包括 ,也可以嵌套

3. 在組件的定義中,除了template之外的其他選項—data,computed,methods

4. data必須是一個方法

<div id="app" v-cloak>      
    <button-component></button-component>  
</div>
components:{      
    'button-component':{        
        template: '<button @click="count+=1">{{count}}</button>',        
        data: function(){          
            return { count: 0  }        
        }      
    }    
}

使用props傳遞數(shù)據(jù) 父親向兒子傳遞數(shù)據(jù)

1. 在組件中使用props來從父親組件接收參數(shù),注意,在props中定義的屬性,都可以在組件中直接使用

2. props來自父級,而組件中data return的數(shù)據(jù)就是組件自己的數(shù)據(jù),兩種情況作用域就是 組件本身,可以在template,computed,methods中直接使用

3. props的值有兩種,一種是字符串數(shù)組,一種是對象,本節(jié)先只講數(shù)組

4. 可以使用v--bind動態(tài)綁定父組件來的內容

父組件傳數(shù)據(jù)給子組件

<div id="app" v-cloak>    
    <p>我是父組件</p>      
    <child-component message="聽媽媽的話,別讓她受傷"></child-component>  
</div>

var app = new Vue({    
    el: '#app',    
    components:{      
        'child-component':{        
            props:['message'],        
            template: '<button>{{message}}</button>'      
        }    
    }  
})

使用v--bind動態(tài)綁定父組件來的內容

<div id="app" v-cloak>    
    <input type="text" v-model="message">    
    <child-component :msg="message"></child-component>  
</div>

var app = new Vue({    
    el: '#app',    
    data:{message: ''},    
    components:{      
        'child-component':{        
            props:['msg'],        
            template: '<button>{{msg}}</button>'      
        }    
    }  
})

效果

input輸入框里的內容會同步到子組件button按鈕內

image.png

單向數(shù)據(jù)流

解釋 : 通過 props 傳遞數(shù)據(jù)是單向的,也就是父組件數(shù)據(jù)變化時會傳遞給子組件,但是反過來不行

目的 :是盡可能將父子組件解稿,避免子組件無意中修改了父組件的狀態(tài)。

應用場景: 業(yè)務中會經常遇到兩種需要改變 prop 的情況

一種是父組件傳遞初始值進來,子組件將它作為初始值保存起來,在自己的作用域下可以隨意使用和修改。這種情況可以在組件 data 內再聲明一個數(shù)據(jù),引用父組件 的 prop

步驟一:注冊組件

步驟二:將父組件的數(shù)據(jù)傳遞進來,并在子組件中用props接收

步驟三:將傳遞進來的數(shù)據(jù)通過初始值保存起來

<div id="app">    
    <my-component init-count="666"></my-comp>  
</div>
var app = new Vue({    
    el: '#app',    
    components: {      
        'my-component': {        
            props: ['init-count'],        
            template: '<div>{{count}}</div>',        
            data: function () {          
                return {            
                count: this.initCount          
                }        
            }      
        }    
    }  
})

另一種情況就是 prop 作為需要被轉變的原始值傳入。這種情況用計算屬性就可以了

步驟一:注冊組件

步驟二:將父組件的數(shù)據(jù)傳遞進來,并在子組件中用props接收

步驟三:將傳遞進來的數(shù)據(jù)通過計算屬性進行重新計算

通過計算屬性動態(tài)控制元素的寬度

<div id="app" v-cloak>    
    <input type="text" v-model="width">    
    <child-component :width="width"></child-component>  
</div>

var app = new Vue({    
    el: '#app',    
    data:{width: 0 },    
    components:{      
        'child-component':{        
            props:['width'],        
            template: '<div :style="style"></div>',        
        computed:{          
            style: function(){            
                return {              
                width: this.width+'px',              
                height: '20px',              
                background: 'grey'            
                    }          
                }        
            }      
        }    
    }  
})

數(shù)據(jù)驗證

vue組件中camelCased (駝峰式) 命名與 keba-b-case(短橫線命名)

1. 在html中, myMessage 和 mymessage 是一致的,,因此在組件中的html 中使用必須使用kebab--case(短橫線)命名方式。在html中不允許使用駝峰?。。?/strong>

2. 在組件中, 父組件給子組件傳遞數(shù)據(jù)必須用短橫線。在template中,必須使用駝峰命名,若為短橫線的命名方式。則會直接保錯。

3. 在組件的data中,用this.XXX引用時,只能是駝峰命名方式。若為短橫線的命名方式,則會報錯。

驗證的 type 類型可以是:

? String

? Number

? Boolean

? Object

? Array

? Function

Vue.component ( 'my-compopent', {
props : {
//必須是數(shù)字類型
propA : Number ,
//必須是字符串或數(shù)字類型
propB : [String , Number] ,
//布爾值,如果沒有定義,默認值就是 true
propC: {
type : Boolean ,
default : true
},
//數(shù)字,而且是必傳
propD: {
type: Number ,
required : true
},
//如果是數(shù)組或對象,默認值必須是一個函數(shù)來返回
propE: {
type : Array ,
default : function () {
return [] ;
}
},
//自定義一個驗證函數(shù)
propF: {
validator : function (value) {
return value > 10;}
}
}
})

自定義事件—子組件給父組件傳遞數(shù)據(jù)

使用v--on 除了監(jiān)昕 DOM 事件外,還可以用于組件之間的自定義事件。 JavaScript 的設計模式 一一觀察者模式, dispatchEvent 和 addEventListener這兩個方法。 Vue 組件也有與之類似的一套模式,子組件用emit()來 觸發(fā)事件 ,父組件用on()來 監(jiān)昕子組件的事件 。 直接甩代碼

第一步:自定義事件

第二步: 在子組件中用$emit觸發(fā)事件,第一個參數(shù)是事件名,后邊的參數(shù)是要傳遞的數(shù)據(jù)

第三步:在自定義事件中用一個參數(shù)來接受

<div id="app">    
    <p>要買多少個蘋果? {{number}}</p>    
    <child-component @change="change"></child-component>  
</div>
var app = new Vue({    
    el: '#app',    
    data: {      number: 200    },    
    methods: {      
        change: function (value) {        
        this.number = value      
        }    
    },    
    components: {      
        'child-component': {           
        data: function () {          
            return { count: 200  }        
    },        
    template: `<div><button @click="add">+1</button><button @click="reduce">-1</button></div>`,        
    methods: {          
        add: function () {            
                this.count += 1            
                this.$emit('change', this.count)          
        },          
        reduce: function () {            
            this.count -= 1            
            this.$emit('change', this.count)          
                }        
            }      
        }    
    }  
})

效果:

image.png

在組件中使用v--model

$emit的代碼,這行代碼實際上會觸發(fā)一個 input事件, ‘input’后的參數(shù)就是傳遞給v--model綁定 的屬性的值 v--model 其實是一個語法糖,這背后其實做了兩個操作

  • v--bind 綁定一個 value 屬性
  • v--on 指令給當前元素綁定 input 事件

要使用v--model,要做到:

  • 接收一個 value 屬性。
  • 在有新的 value 時觸發(fā) input 事件
<div id="app">    
    <p>您要買多少個蘋果? {{number}}</p>    
    <child-component v-model="number"></child-component>  
</div>
var app = new Vue({    
    el: '#app',    
    data: {      
        number: 200    
    },    
    components: {      
        'child-component': {        
    data:function(){return{count:200}},        
    template: `<button @click="add">+1</button>`,        
    methods: {          
        add: function () {            
            this.count += 1        
----------------------注意觀察.這一行,emit的是input事件----------------    
            this.$emit('input', this.count)          
            }        
        }      
    }    
}  
})

非父組件之間的通信

可以用一個空的Vue實例作為中央事件總線:

var bus = new Vue()
// 觸發(fā)事件
bus.$emit('事件名', 1)
//如果是子組件, this.$root.bus

// 監(jiān)聽事件
bus.$emit('事件名', function(id){
    // .....
})

代碼:

<div id="app">    
    <my-component></my-component>    
    <child-component></child-component>  
</div>
var app = new Vue({    
    el: '#app',    
    data: { bus: new Vue() },    
    components: {      
        'my-component': {        
        data:function(){          
            return {            
                text: '我是A組件里的text'          
            }        
        },        
    template: '<div><button @click="onclick">點我</button></div>',        
    methods:{          
        onclick: function(){            
            this.$root.bus.$emit('send',this.text)          
            }        
        }      
    },      
    'child-component': {        
        template: '<div>第二個組件</div>',        
        created: function(){          
            this.$root.bus.$on('send',function(value){            
            alert(value)          
                })        
            }      
        }    
    }  
})

點擊A組件里的按, 就會觸發(fā)send事件, 同時把數(shù)據(jù)發(fā)出去, B組件監(jiān)聽send事件, 獲取傳過來的數(shù)據(jù)

父鏈: this.$parent

this.$parent.msg = '數(shù)據(jù)已經修改了'

子鏈:

this.$refs 提供了為子組件提供索引的方法,用特殊的屬性ref為其增加一個索引

// 給子組件添加ref屬性
this.formchild = this.$refs.c.msg;

使用slot分發(fā)內容

什么是slot(插槽)

為了讓組件可以組合,我們需要一種方式來混合父組件的內容與子組件自己的模板。這個過程被稱為內容分發(fā). Vue.js 實現(xiàn)了一個內容分發(fā)API,使用特殊的 ‘slot’ 元素作為原始內容的插槽

編譯的作用域

在深入內容分發(fā) API 之前,我們先明確內容在哪個作用域里編譯。假定模板為:

<child-component>
    {{ message }} 
</child-component>

message 應該綁定到父組件的數(shù)據(jù),還是綁定到子組件的數(shù)據(jù)?答案是父組件。組件作用 域簡單地說是:

父組件模板的內容在父組件作用域內編譯;

子組件模板的內容在子組件作用域內編譯。

插槽的用法

父組件的內容與子組件相混合,從而彌補了視圖的不足

混合父組件的內容與子組件自己的模板

單個插槽:

<div id="app">    
    <child-component>     
        slot, 接著    
    </child-component>  
</div>

components: {      
    'child-component': {
        template: `<div><slot>如果父組件沒有插入內容,我就作為默認出現(xiàn)</slot></div>`      
    }    
}

具名插槽:

模板占位slot 通過slot 和name屬性進行關聯(lián)

<div id="app">    
    <child-component>      
        <p slot="header">我是標題</p>      
        <p>文本內容第一部分</p>      
        <p>文本內容第二部分</p>      
        <p slot="footer">我是頁腳</p>    
</child-component></div>
components: {      
    'child-component': {        
        template: `<div>                    
            <div class="header">                      
                <slot name="header"></slot>                    
            </div>                    
            <div>                      
                <slot></slot>                    
            </div>                    
            <div class="footer">                      
                <slot name="footer"></slot>                    
            </div>                  
        </div>                  `      
    }    
}

效果:

image.png

作用域插槽:

作用域插槽是一種特殊的slot,使用一個可以復用的模板來替換已經渲染的元素 ——從子組件獲取數(shù)據(jù) ,template模板是不會被渲染的

<child-component>      
    <template slot="child" slot-scope="parent">        
        {{parent.text}}      
    </template>    
</child-component>
components: {      
    'child-component': {        
    template: `          
        <div>            
            <slot text="子組件里的text" name="child"></slot>          
        </div>`      
    }    
}

Vue 2.5.0之前, slot-scope只能寫在template標簽上

訪問slot

通過this.$slots.(NAME)

mounted:function () { 
    //訪問插槽
    var header = this.$slots.header;
    var text = header[0].elm.innerText;
    var html = header[0].elm.innerHTML;
    console.log(header)
    console.log(text)
    console.log(html)
}

組件高級用法–動態(tài)組件

VUE給我們提供了一個元素叫component 作用是:

用來動態(tài)的掛載不同的組件

實現(xiàn):使用is特性來進行實現(xiàn)的

// 點擊不同的按鈕, 渲染不同的組件

<div id="app">    
    <component :is="thisView"></component>    
    <button @click="selected('A')">一</button>    
    <button @click="selected('B')">二</button>    
    <button @click="selected('C')">三</button>  
</div>
var app = new Vue({    
    el: '#app',    
    data: {  thisView: 'compA' },    
    methods:{      
        selected:function(tag){        
        this.thisView = 'comp' + tag      
        }    
    },    
    components: {      
        'compA': {        
            template: '<div>一個和尚挑水喝</div>'      
        },      
        'compB': {        
            template: '<div>兩個和尚抬水喝</div>'      
        },      
        'compC': {        
            template: '<div>三個和尚沒水喝</div>'      
        }    
    }  
})
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容