組件通信
- 爲什麼要進行組件通信?
組件可以說是一個具有獨立功能的整體,但是當我們要將這些組件拼接在一起時,這些組件相互之間要建立聯繫
,這個聯繫我們就稱之爲通信 - 組件通信的方式有以下幾種( 王者級 )
- 父子組件通信
使用props來實現
- 父子組件通信
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h3> 這裏是父組件 </h3>
<hr>
<Son :aa = "money" :mask-flag = "maskFlag" :maskFlag = "maskFlag"/>
</div>
</template>
<template id="son">
<div>
<h3> 這裏是son組件 </h3>
<p> 父親給了我 {{ aa }} 錢 </p>
<p> {{ maskFlag }} </p>
</div>
</template>
Vue.component('Father',{
template: '#father',
data () { // 爲什麼要將data定義爲函數?
return {
money: 2000,
maskFlag: 10000000000
}
}
})
Vue.component('Son',{
template: '#son',
props: ['aa','maskFlag']
})
new Vue({
}).$mount('#app')
props
1. 在父組件的模板中將數據用單項數據綁定的形式,綁定在子組件身上
2. 在子組件的配置項中可以使用一個props配置項來接收這個數據,接收時,props的取值可以使一個數組
Vue.component('Son',{
template: '#son',
props: ['money']
})
-
在子組件模板中,接收到的屬性可以像全局變量一樣直接使用
父親給了我 {{ money }} 錢
問題: 爲什麼data要定義爲一個函數?
1. 組件是一個獨立的個體,那麼它應該擁有自己的數據,這個數據應該是一個獨立的數據
2. 也就是說這個數據應該有獨立作用域,也就是有一個獨立的使用範圍,這個範圍就是這個組件內
3. js的最大特徵是:函數式編程 , 而函數恰好提供了獨立作用域
問題: 爲什麼data要有返回值?返回值還是一個對象?
1. 因爲Vue是通過observer來觀察data選項的,所有必須要有返回值
2. 因爲Vue要通過es5的Object.defineProperty屬性對對象進行getter和setter設置 -
子父組件通信
自定義事件
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h3> 這裏father組件 </h3>
<p> 兒子給了我 {{ money }} </p>
<Son @give = "getHongbao"/>
</div>
</template>
<template id="son">
<div>
<button @click = "giveFather"> give </button>
<h3> 這裏是son組件 </h3>
</div>
</template>
Vue.component('Father',{
template: '#father',
data () {
return {
money: 0
}
},
methods: {
getHongbao ( val ) {
console.log( 1 )
this.money = val
}
}
})
Vue.component('Son',{
template: '#son',
data () {
return {
hongbao: 500
}
},
methods: {
giveFather () {
//如何進行父組件給子組件的自定義事件觸發
this.$emit('give',this.hongbao)
}
}
})
new Vue({
el: '#app'
})
註釋
自定義事件
1. 自定義的 通過 $on 定義 $emit觸發
2. 通過綁定在組件身上定義,通過 $emit觸發
子父通信流程
1. 在父組件的模板中,通過事件綁定的形式,綁定一個自定義事件在子組件身上
<Son @aa = “fn”/> //這邊要注意: fn是要在父組件配置項methods中定義
- 在子組件的配置項methods中寫一個事件處理程序,在事件處理程序中觸發父組件綁定的自定義事件
Vue.component('Son',{
template: '#son',
data () {
return {
hongbao: 500
}
},
methods: {
giveFather () {
//如何進行父組件給子組件的自定義事件觸發
this.$emit('give',this.hongbao)
}
}
})
- 將子組件定義的事件處理程序 giveFather,綁定在子組件的按鈕身上
<template id="son">
<div>
<button @click = "giveFather"> give </button>
<h3> 這裏是son組件 </h3>
</div>
</template>
- 非父子組件通信
ref鏈: 可以實現非父子組件的通信,但是如果層級太多,就比較繁瑣了 $attrs
<div id="app">
<Father></Father>
</div>
<template id="father">
<!-- 組件中根元素必須唯一 -->
<div>
<h3> 這裏是father </h3>
<button @click = "look"> 點擊查看father的this </button>
<p> father的 n: {{ n }} </p>
<hr>
<Son ref = "son"></Son>
<Girl ref = "girl" :n = "n"></Girl>
</div>
</template>
<template id="son">
<div>
<h3> 這裏是 son 1 </h3>
</div>
</template>
<template id="girl">
<div>
<h3> 這裏是girl </h3>
<button @click = "out"> 輸出girl的this </button>
</div>
</template>
Vue.component('Father',{
template: '#father',
data () {
return {
n: 0
}
},
methods: {
look () {
this.n = this.$refs.son.money
}
}
})
Vue.component('Son',{
template: '#son',
data () {
return {
money: 1000
}
}
})
Vue.component('Girl',{
template: '#girl',
data () {
return {
num: 0
}
},
methods: {
out () {
console.log( this )
console.log( this.$attrs )
}
}
})
new Vue({
el: '#app'
})
bus事件總線
<div id="app">
<Bro></Bro>
<Sma></Sma>
</div>
<template id="big">
<div>
<h3> 這裏是哥哥組件 </h3>
<button @click = "hick"> 揍 </button>
</div>
</template>
<template id="small">
<div>
<h3> 這裏是弟弟組件 </h3>
<p v-show = "flag"> 嗚嗚嗚嗚嗚嗚嗚嗚嗚uwuwuwuwu </p>
</div>
</template>
var bus = new Vue() // bus原型上是不是有 $on $emit
Vue.component('Bro',{
template: '#big',
methods: {
hick () {
bus.$emit('aa')
}
}
})
Vue.component('Sma',{
template: '#small',
data () {
return {
flag: false
}
},
mounted () { //當前組件掛載結束,也就是我們可以在頁面當中看到真實dom
// mounted這個鉤子函數的觸發條件是組件創建時會自動觸發
// 事件的聲明
var _this = this
bus.$on( 'aa',function () {
_this.flag = true
console.log( this )//這裏是this指的是bus, 但是我們需要的this應該是Sma這個組件
})
}
})
new Vue({
el: '#app'
})
註釋
bus事件總線,我們是通過 $on來定義事件, 通過 $emit來觸發事件
案例: 哥哥揍弟弟,弟弟哭
流程:
1. 在其中一個組件的 掛載鉤子函數 上 做事件的聲明
Vue.component('Sma',{
template: '#small',
data () {
return {
flag: false
}
},
mounted () { //當前組件掛載結束,也就是我們可以在頁面當中看到真實dom
// mounted這個鉤子函數的觸發條件是組件創建時會自動觸發
// 事件的聲明
var _this = this
bus.$on( 'aa',function () {
_this.flag = true
console.log( this )//這裏是this指的是bus, 但是我們需要的this應該是Sma這個組件
})
}
})
- 在另一個組件中 通過 bus.$emit(‘aa’)來觸發這個自定義事件
app實例的手動掛載
new Vue({
}).$mount('#app')
自定義事件
-
自定義的 通過 $on 定義 $emit觸發
var vm = new Vue({ el: '#app' }) // 自定義事件的定義( 發佈 ) // vm.$on(自定義事件的名稱,自定義事件的事件處理程序) vm.$on( 'aa', function () { console.log( 'aa' ) }) //自定義事件的觸發 ( 訂閱 ) // vm.$emit( 自定義事件的名稱,自定義事件處理程序需要的參數1,參數2,參數3) vm.$emit( 'aa' )
-
通過綁定在組件身上定義,通過 $emit觸發
<Son @aa = “fn”/>使用: 子父通信
組件的根元素必須有且僅有一個
動態組件
- 什麼是動態組件?
可以改變的組件 - 使用
通過 Vue 提供了一個 component + is 屬性 - 動態組件指的就是 component這個組件
- 案例
<div id="app"> <button @click = "change"> 切換 </button> <keep-alive include=""> <component :is = "type"></component> </keep-alive> </div>
Vue.component('Aa',{ template: '<div> Aa </div>' }) Vue.component('Bb',{ template: '<div> Bb </div>' }) new Vue({ data: { type: 'Aa' }, methods: { change () { this.type = (this.type === 'Aa'?'Bb':'Aa') } } }).$mount('#app')
- Vue提供了一個叫做 keep-alive 的組件可以將我們的組件進行瀏覽器緩存,這樣當我們切換組件時,就可以大大提高使用效率
- keep-alive也可以以屬性的形式呈現,但是我們如果搭配component的話,建議使用組件的形式
<div id="app">
<button @click = "change"> 切換 </button>
<!-- <keep-alive include="">
<component :is = "type"></component>
</keep-alive> -->
<component :is = "type"></component>
</div>
Vue.component('Aa',{
template: '<div> Aa </div>'
})
Vue.component('Bb',{
template: '<div> Bb </div>'
})
new Vue({
data: {
type: 'Aa'
},
methods: {
change () {
this.type = (this.type === 'Aa'?'Bb':'Aa')
}
}
}).$mount('#app')
slot 插槽
- 作用/概念: 預先將將來要使用的內容進行保留
<div id="app">
<Hello>
<div>
這裏是地球
</div>
</Hello>
</div>
<template id="hello">
<div>
<slot></slot>
<h3>這裏是hello</h3>
</div>
</template>
Vue.component('Hello',{
template: '#hello'
})
new Vue({
el: '#app'
})
運行結果:‘這裏是地球’會插在這裏是hello的前面
2. 具名插槽: 給slot起個名字
<div id="app">
<Hello>
<header slot = 'header'> 這裏是頭部 </header>
<footer slot = 'footer'> 這裏是底部 </footer>
</Hello>
</div>
<template id="hello">
<div>
<slot name = "header"></slot>
<h3>這裏是hello</h3>
<slot name = "footer"></slot>
</div>
</template>
Vue.component('Hello',{
template: '#hello'
})
new Vue({
el: '#app'
})
運行結果:
- 注意: 以上兩種形式在 vue2.6以上被廢棄