目錄
引入
父組件==>子組件
子組件==>父組件
全局事件總線
消息訂閱與發(fā)布
引入
你知道Vue中組件之間應(yīng)該如何進(jìn)行通信嗎?這里面就涉及到了多個關(guān)系了,父子之間互傳、兄弟之間互傳、子孫之間互傳,甚至是任意的組件之間傳遞......
是不是感覺有點頭皮發(fā)麻。沒關(guān)系,本文將帶領(lǐng)大家一起學(xué)習(xí)對應(yīng)的解決方法!??!
父組件==>子組件
父組件若想傳遞信息給子組件,最常見的方式就是使用props配置項。該配置項的功能是讓組件接受外部傳過來的數(shù)據(jù)。
傳遞數(shù)據(jù):<Demo name="xxx"/>
接收數(shù)據(jù):
1.第一種方式(只接收):props:['name']
2.第二種方式(限制類型):props:{name:String}
3.第三種方式(限制類型、限制必要性、指定默認(rèn)值):
props:{
name:{
type:String, //類型
required:true, //必要性
default:'老王' //默認(rèn)值
}
}
現(xiàn)在在腳手架中編寫一個案例來實現(xiàn)父組件給子組件傳遞數(shù)據(jù),并在頁面上顯示出來。默認(rèn)的父組件為App, 子組件為Student。先從父組件傳入三個數(shù)據(jù)給子組件,并且顯示在頁面上。接受方式分別采用以上的方式來實現(xiàn),對應(yīng)的代碼如下:
App.vue
<template>
<div>
<!-- 為子組件傳入數(shù)據(jù) -->
<Student name="N-A" sex="男" age="5"/>
</div>
</template>
?
<script>
? ?//導(dǎo)入Student組件
import Student from './components/Student'
export default {
name:'App',
? ?//注冊Student組件
components:{Student}
}
</script>
?
Student.vue
<template>
<div>
<h1>{{msg}}</h1>
<h2>博主姓名:{{name}}</h2>
<h2>博主性別:{{sex}}</h2>
<h2>博主年齡:{{age}}</h2>
</div>
</template>
<script>
export default {
? ? ? ?//組件名命名為Student
name:'Student',
data() {
return {
msg:'我是一名CSDN博主'
}
},
//方式一:簡單聲明接收
props:['name','sex',"age"]
?
//方式二:接收的同時對數(shù)據(jù)進(jìn)行類型限制
props:{
name:String,
age:Number,
sex:String
}
?
//方式三:接收的同時對數(shù)據(jù):進(jìn)行類型限制+默認(rèn)值的指定+必要性的限制
props:{
name:{
type:String, //name的類型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默認(rèn)值
},
sex:{
type:String,
required:true
}
}
}
</script>
分別運行以上代碼提供的三種方式運行的效果圖如上,三種方式都能夠讓數(shù)據(jù)在頁面上進(jìn)行顯示。但是其中涉及到一些問題。圖二為采用方式二來接收傳入的數(shù)據(jù)時的控制臺出現(xiàn)的錯誤,雖然能夠在頁面上看到數(shù)據(jù),但是已經(jīng)存在問題了,因為我們在接收數(shù)據(jù)時規(guī)定了age屬性傳入的數(shù)據(jù)的類型為number類型。
但是我們在傳值時,編寫了age="5", 因此傳入的5則為字符串。那該如何解決呢?只需要在age前面加上冒號。對其進(jìn)行綁定,綁定之后雙引號之中的東西都會當(dāng)成是JS的表達(dá)式去解析,因此,解析之后就是純粹的數(shù)字5,因此就能夠解決相應(yīng)的問題。
現(xiàn)在我在增加一個要求,在頁面上增加一個按鈕通過點擊之后來實現(xiàn)頁面上的年齡加一的效果。對應(yīng)代碼如下:
<template>
<div>
<h1>{{msg}}</h1>
<h2>博主姓名:{{name}}</h2>
<h2>博主性別:{{sex}}</h2>
<h2>博主年齡:{{MyAge}}</h2>
<button @click="updateAge">年齡加一</button>
</div>
</template>
?
<script>
export default {
name:'Student',
data() {
return {
msg:'我是一名CSDN博主',
MyAge:this.age
}
},
methods: {
updateAge(){
this.MyAge++
}
},
//簡單聲明接收
props:['name','age','sex']
}
</script>
效果能夠正常顯示。看了以上的代碼可能會有小伙伴會問,為啥子組件接收到的age數(shù)據(jù)不直接修改呢,直接修改也能夠?qū)崿F(xiàn)相應(yīng)的效果。為啥還需要另一個設(shè)置MyAge來接收它,再修改MyAge的值呢?這時候就需要注意一下以下的注意事項了。
注意:props是只讀的,Vue底層會監(jiān)測你對props的修改,如果進(jìn)行了修改,就會發(fā)出警告,若業(yè)務(wù)需求確實需要修改,那么請復(fù)制props的內(nèi)容到data中一份,然后去修改data中的數(shù)據(jù)。
子組件==>父組件
實現(xiàn)方法一:通過父組件給子組件傳遞函數(shù)類型的props,從而實現(xiàn)子組件給父組件傳遞數(shù)據(jù)。在前面我們已經(jīng)對props有了一定的了解了,那么現(xiàn)在我們就來通過代碼實現(xiàn)吧!
案例:School組件有學(xué)校名以及學(xué)校地址兩個信息,現(xiàn)在需要實現(xiàn)App父組件可以接收到School子組件傳過來的學(xué)校名。
App.vue(父組件)
<template>
<div class="app">
<!-- 通過父組件給子組件傳遞函數(shù)類型的props實現(xiàn):子給父傳遞數(shù)據(jù) -->
<School :getSchoolName="getSchoolName"/>
</div>
</template>
?
<script>
import School from './components/School'
export default {
name:'App',
components:{School},
methods: {
getSchoolName(name){
console.log('App收到了學(xué)校名:',name)
}
}
}
</script>
?
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
</style>
在App父組件中,定義了一個getSchoolName函數(shù),并為子組件傳遞了該函數(shù)。
School.vue(子組件)
<template>
<div class="school">
<h2>學(xué)校名稱:{{name}}</h2>
<h2>學(xué)校地址:{{address}}</h2>
<button @click="sendSchoolName">把學(xué)校名給App</button>
</div>
</template>
?
<script>
export default {
name:'School',
props:['getSchoolName'],
data() {
return {
name:'史萊克學(xué)院',
address:'天斗帝國',
}
},
methods: {
sendSchoolName(){
this.getSchoolName(this.name)
}
},
}
</script>
?
<style scoped>
.school{
background-color:rgb(212, 237, 210);
padding: 5px;
}
</style>
子組件使用props配置項接收了getSchoolName函數(shù),在sendSchoolName函數(shù)中調(diào)用傳過來的函數(shù),并傳入學(xué)校名。并為按鈕綁定getSchoolName點擊事件。通過點擊之后來實現(xiàn)向父組件傳遞學(xué)校名的目的。對應(yīng)的實現(xiàn)效果如下:
實現(xiàn)方法二:若子組件想要傳數(shù)據(jù)給父組件,還可以使用組件的自定義事件。使用場景為:若A是父組件,B是子組件,B想給A傳數(shù)據(jù),那么就要在A中給B綁定自定義事件(事件的回調(diào)在A中)。
綁定自定義事件有如下的兩種方式:
第一種方式,在父組件中:<Demo @自定義事件名="test"/>
或 <Demo v-on:自定義事件名="test"/>
案例還是上面的,通過修改第一種方式的自定義事件對應(yīng)的代碼如下:
App.vue(父組件)
<template>
<div class="app">
<!-- 通過父組件給子組件綁定一個自定義事件實現(xiàn):子給父傳遞數(shù)據(jù)(第一種寫法,使用@或v-on) -->
<School @showName="getSchoolName"/>
</div>
</template>
?
<script>
import School from './components/School'
export default {
name:'App',
components:{School},
methods: {
getSchoolName(name){
console.log('App收到了學(xué)校名:',name)
}
},
}
</script>
?
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
</style>
?
School.vue(子組件)
<template>
<div class="school">
<h2>學(xué)校名稱:{{name}}</h2>
<h2>學(xué)校地址:{{address}}</h2>
<button @click="sendSchoolName">把學(xué)校名給App</button>
</div>
</template>
?
<script>
export default {
name:'School',
data() {
return {
name:'史萊克學(xué)院',
address:'天斗帝國',
}
},
methods: {
sendSchoolName(){
//觸發(fā)School組件實例身上的showName事件
this.$emit('showName',this.name)
}
},
}
</script>
?
<style scoped>
.school{
background-color:rgb(212, 237, 210);
padding: 5px;
}
</style>
實現(xiàn)效果如下:能夠正常的顯示出來!
第二種方式,只是在父組件中換一種綁定事件的方式,只需要修改父組件中代碼:
<template>
<div class="app">
<!-- 通過父組件給子組件綁定一個自定義事件實現(xiàn):子給父傳遞數(shù)據(jù)(第二種寫法,使用ref) -->
<School ref="school" />
</div>
</template>
<script>
import School from './components/School'
export default {
name:'App',
components:{School},
methods: {
getSchoolName(name){
console.log('App收到了學(xué)校名:',name)
}
},
mounted() {
this.$refs.school.$on('showName',this.getSchoolName) //綁定自定義事件
},
}
</script>
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
</style>
實現(xiàn)效果與之上的相同。關(guān)于自定義事件的其他知識點,我就不在這里過多贅述,畢竟主要是分享它如何實現(xiàn)子組件向父組件傳數(shù)據(jù)。
注意:通過this.$refs.xxx.$on('atguigu',回調(diào))
綁定自定義事件時,回調(diào)要么配置在methods中,要么用箭頭函數(shù),否則this指向會出問題!
全局事件總線
全局事件總線是一種組件間通信的方式,適用于任意組件間通信。
1.安裝全局事件總線:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安裝全局事件總線,$bus就是當(dāng)前應(yīng)用的vm
},
? ?......
})
2.使用事件總線:
- 接收數(shù)據(jù):A組件想接收數(shù)據(jù),則在A組件中給$bus綁定自定義事件,事件的回調(diào)留在A組件自身。
methods(){
?demo(data){......}
}
......
mounted() {
?this.$bus.$on('xxxx',this.demo)
}
- 提供數(shù)據(jù):
this.$bus.$emit('xxxx',數(shù)據(jù))
3.最好在beforeDestroy鉤子中,用$off去解綁當(dāng)前組件所用到的事件。
案例:現(xiàn)有兩個兄弟組件,分別是Student組件以及School組件,要實現(xiàn)Student組件給School組件傳送數(shù)據(jù)。對應(yīng)的實現(xiàn)代碼如下:
main.js入口文件,需要先安裝全局事件總線。
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//關(guān)閉Vue的生產(chǎn)提示
Vue.config.productionTip = false
?
//創(chuàng)建vm
new Vue({
el:'#app',
render: h => h(App),
//安裝全局事件總線
beforeCreate() {
Vue.prototype.$bus = this
}
})
提供數(shù)據(jù)方組件代碼如下:
<template>
<div class="student">
<h2>學(xué)生姓名:{{name}}</h2>
<h2>學(xué)生性別:{{sex}}</h2>
<button @click="sendStudentName">把學(xué)生名給School組件</button>
</div>
</template>
?
<script>
export default {
name:'Student',
data() {
return {
name:'N-A',
sex:'男',
}
},
methods: {
? ? ? ? ? ?//提供數(shù)據(jù)
sendStudentName(){
this.$bus.$emit('hello',this.name)
}
},
}
</script>
?
<style ?scoped>
.student{
background-color:rgb(212, 237, 210);
padding: 5px;
margin-top: 30px;
}
</style>
接收數(shù)據(jù)方組件代碼如下:
<template>
<div class="school">
<h2>學(xué)校名稱:{{name}}</h2>
<h2>學(xué)校地址:{{address}}</h2>
</div>
</template>
?
<script>
export default {
name:'School',
data() {
return {
name:'史萊克學(xué)院',
address:'天斗帝國',
}
},
? ? ? ?//綁定一個hello事件,用于接收數(shù)據(jù)
mounted() {
this.$bus.$on('hello',(data)=>{
console.log('我是School組件,收到了數(shù)據(jù)',data)
})
},
? ? ? ?//用$off去解綁<span style="color:red">當(dāng)前組件所用到的</span>事件。
beforeDestroy() {
this.$bus.$off('hello')
},
}
</script>
?
<style scoped>
.school{
background-color:rgb(212, 237, 210);
padding: 5px;
}
</style>
實現(xiàn)效果如下,兄弟組件之間實現(xiàn)了數(shù)據(jù)的傳遞。
消息訂閱與發(fā)布
消息訂閱與發(fā)布是一種組件間通信的方式,適用于任意組件間通信。使用方式如下:
1.安裝pubsub:npm i pubsub-js
2.引入: import pubsub from 'pubsub-js'
3.接收數(shù)據(jù):A組件想接收數(shù)據(jù),則在A組件中訂閱消息,訂閱的回調(diào)留在A組件自身。
methods(){
?demo(data){......}
}
......
mounted() {
?this.pid = pubsub.subscribe('xxx',this.demo) //訂閱消息
}
4.提供數(shù)據(jù):pubsub.publish('xxx',數(shù)據(jù))
5.最好在beforeDestroy鉤子中,用PubSub.unsubscribe(pid)
去取消訂閱。
該方式與上述的全局事件總線比較相似,主要是不需要用到$bus,而是替換成了pubsub。
對以上的代碼進(jìn)行修改之后如下:
提供數(shù)據(jù)方組件代碼如下:
<template>
<div class="student">
<h2>學(xué)生姓名:{{name}}</h2>
<h2>學(xué)生性別:{{sex}}</h2>
<button @click="sendStudentName">把學(xué)生名給School組件</button>
</div>
</template>
?
<script>
import pubsub from 'pubsub-js'
export default {
name:'Student',
data() {
return {
name:'N-A',
sex:'男',
}
},
methods: {
sendStudentName(){
pubsub.publish('hello',this.name)
}
},
}
</script>
?
<style ?scoped>
.student{
background-color:rgb(212, 237, 210);
padding: 5px;
margin-top: 30px;
}
</style>
接收數(shù)據(jù)方組件代碼如下:
<template>
<div class="school">
<h2>學(xué)校名稱:{{name}}</h2>
<h2>學(xué)校地址:{{address}}</h2>
</div>
</template>
?
<script>
import pubsub from 'pubsub-js'
export default {
name:'School',
data() {
return {
name:'史萊克學(xué)院',
address:'天斗帝國',
}
},
mounted() {
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log(data)
})
},
beforeDestroy() {
pubsub.unsubscribe(this.pubId)
},
}
</script>
?
<style scoped>
.school{
background-color:rgb(212, 237, 210);
padding: 5px;
}
</style>
實現(xiàn)效果如下:
文章來源:http://www.zghlxwxcb.cn/news/detail-648259.html
好啦,本文就到這里結(jié)束了,你學(xué)到了嗎?若有任何的疑問或者問題歡迎各位在評論區(qū)或者私信找我一起交流學(xué)習(xí)!文章來源地址http://www.zghlxwxcb.cn/news/detail-648259.html
到了這里,關(guān)于Vue中 組件間的通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!