Vue3中的常見組件通信之mitt
概述
? 在vue3中常見的組件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的組件關系用不同的傳遞方式。常見的撘配形式如下表所示。
組件關系 | 傳遞方式 |
---|---|
父傳子 | 1. props 2. v-model 3. $refs 4. 默認插槽、具名插槽 |
子傳父 | 1. props 2. 自定義事件 3. v-model 4. $parent 5. 作用域插槽 |
祖傳孫、孫傳祖 | 1. $attrs 2. provide、inject |
兄弟間、任意組件間 | 1. mitt 2. pinia |
? props和自定義事件詳見本人另一篇文章:
Vue3中的常見組件通信之props和自定義事件
下面接著上文來繼續記錄mitt的用法。
3.mitt
mitt與pubsub訂閱消息與發布消息功能類似,它可以實現在任意組件間的通信。
3.1安裝mitt及引入mitt
mitt需要安裝,在終端中輸入命令npm i mitt來安裝。
mitt安裝好之后按照工程化的管理需要在src的文件下新建文件夾utils,然后在utils文件夾中新建文件emitter.ts。
在emitter.ts文件中引入mitt,并創建emitter,同時暴露emitter,如下代碼:
//引入mitt
import mitt from 'mitt'//調用mitt,得到emitter,emitter可以綁定事件和觸發事件
const emitter = mitt()//暴露emitter
export default emitter
之后需要再在main.ts中引入emitter,如下代碼:
import emitter from '@/utils/emitter'
3.2 emitter基本用法
emitter身上有四個方法,分別是
- **on()😗*用來綁定事件,接收兩個參數,第一個參數是事件名,第二個參數是事件觸發時的回調函數;
- **emit()😗*用來觸發事件,參數為事件名;
- **off()😗*用來解綁事件,參數為事件名;
- **all:**all有clear屬性,直接調用clear()屬性可以解綁全部事件。
以下代碼為展示emitter的基本用法:
//綁定事件test1,當事件觸發時執行回調
emitter.on('test1',()=>{console.log('test1被調用了')
})//綁定事件test2,當事件觸發時執行回調
emitter.on('test2',()=>{console.log('test2被調用了')
})//綁定事件test3,當事件觸發時執行回調
emitter.on('test3',()=>{console.log('test3被調用了')
})//觸發事件,每間隔1秒觸發一次
setInterval(()=>{//觸發事件test1emitter.emit('test1')//觸發事件test2emitter.emit('test2')//觸發事件test3emitter.emit('test3')
},1000)//解綁事件,2秒后解綁test1
setTimeout(()=>{emitter.off('test1')console.log('--------test1解綁了')
},2000)//解綁事件,4秒后解綁所有事件
setTimeout(()=>{emitter.all.clear()console.log('--------所有的事件解綁了')
},4000)
運行后在控制臺輸出如下內容:
3.3emitter在組件中的用法
首先創建一個父組件,兩個子組件,父組件代碼如下:
<template><div class="father"><h3>父組件</h3><Child1/><Child2/></div>
</template><script setup lang="ts" name="Father">import Child1 from './Child1.vue'import Child2 from './Child2.vue'
</script><style scoped>.father{margin: 5px;background-color:rgb(79, 186, 111);padding: 20px;color: white;}
</style>
子組件1代碼:
<template><div class="child1"><h3>子組件1</h3></div>
</template><script setup lang="ts" name="Child1"></script><style scoped>.child1{margin: 5px;background-color: rgba(7, 7, 7, 0.224);border: 1px solid;border-color: white;box-shadow: 0 0 5px;padding: 10px;color: #760e0e;}
</style>
子組件2代碼:
<template><div class="child2"><h3>子組件2</h3></div>
</template><script setup lang="ts" name="Child2"></script><style scoped>.child2{margin: 5px;background-color: rgba(255, 255, 255, 0.224);border: 1px solid;border-color: white;box-shadow: 0 0 5px;padding: 10px;color: #05035f;}
</style>
運行效果如下:
然后我們在子組件1中準備一些數據如下:
//數據
let book = reactive({name:'西游記',author:'吳承恩',price:119.95
})
然后在頁面中展示:
<!-- 展示 -->
<h4>圖書名稱:{{ book.name }}</h4>
<h4>圖書作者:{{ book.author }}</h4>
<h4>圖書價格:¥{{ book.price }}</h4>
運行效果如下:
接下來在子組件2中引入emitter,然后創建book數據,給emitter綁定事件,并傳入回調函數:
//引入emitterimport emitter from '@/utils/emitter';import { reactive } from 'vue';//數據let book = reactive({name:'',author:'',price:null})//給emitter綁定getBook事件,傳入回調函數,回調函數接收一個參數emitter.on('getBook',(value:any)=>{// console.log(value)book.name = value.namebook.author = value.authorbook.price = value.price})
然后在子組件1中創建一個按鈕,綁定click事件,觸發getBook事件,并傳遞book參數:
<button @click="emitter.emit('getBook',book)">將book信息發送給子組件2</button>
最后在子組件2中展示接收的到的信息:
<!-- 展示 --><h4>圖書名稱:{{ book.name }}</h4><h4>圖書作者:{{ book.author }}</h4><h4>圖書價格:¥{{ book.price }}</h4>
最后運行后頁面效果如下:
點擊按鈕后效果如下:
至此已經完成了子組件1向子組件2通信。
子組件1完整代碼如下:
<template><div class="child1"><h3>子組件1</h3><!-- 展示 --><h4>圖書名稱:{{ book.name }}</h4><h4>圖書作者:{{ book.author }}</h4><h4>圖書價格:¥{{ book.price }}</h4><button @click="emitter.emit('getBook',book)">將book信息發送給子組件2</button></div>
</template><script setup lang="ts" name="Child1">import emitter from '@/utils/emitter';import { reactive } from 'vue';//數據let book = reactive({name:'西游記',author:'吳承恩',price:119.95})
</script><style scoped>.child1{margin: 5px;background-color: rgba(7, 7, 7, 0.224);border: 1px solid;border-color: white;box-shadow: 0 0 5px;padding: 10px;color: #760e0e;}
</style>
子組件2 的完整代碼如下:
<template><div class="child2"><h3>子組件2</h3><!-- 展示 --><h4>圖書名稱:{{ book.name }}</h4><h4>圖書作者:{{ book.author }}</h4><h4>圖書價格:¥{{ book.price }}</h4></div>
</template><script setup lang="ts" name="Child2">//引入emitterimport emitter from '@/utils/emitter';import { reactive } from 'vue';//數據let book = reactive({name:'',author:'',price:null})//給emitter綁定getBook事件,傳入回調函數,回調函數接收一個參數emitter.on('getBook',(value:any)=>{// console.log(value)book.name = value.namebook.author = value.authorbook.price = value.price})
</script><style scoped>.child2{margin: 5px;background-color: rgba(255, 255, 255, 0.224);border: 1px solid;border-color: white;box-shadow: 0 0 5px;padding: 10px;color: #05035f;}
</style>
3.4 小結
接收數據的組件必須要先綁定事件(訂閱),發送數據的組件要觸發事件,只要組件中引入了emitter,并執行了emitter.emit()代碼并傳遞參數,即可實現任意組件間的通信。