在 Vue3 中,组件之间的通信是构建应用程序的关键
1. 父组件向子组件传递数据 (Props)
这是最基本也是最常用的通信方式。父组件通过属性向子组件传递数据。
「父组件:」
<template>
<child :name="name"></child>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const name = ref('青阳子')
</script>
「子组件:」
<template>
<div>{{ props.name }}</div>
</template>
<script setup>
const props = defineProps({
name: {
type: String,
default: '',
},
})
</script>
2. 子组件向父组件传递数据 (Emit)
子组件可以通过触发事件的方式向父组件传递数据。
「父组件:」
<template>
<child @greet="handleGreet"></child>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const handleGreet = (message) => {
console.log(message) // 输出: "来自子组件的消息"
}
</script>
「子组件:」
<template>
<button @click="handleClick">点击我</button>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const message = ref('来自子组件的消息')
const emits = defineEmits(['greet'])
const handleClick = () => {
emits('greet', message.value)
}
</script>
3. 任意组件通信 (Mitt)
与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信。首先,安装 mitt:
npm install --save mitt
然后,在 main.js 中全局配置:
import { createApp } from 'vue'
import mitt from 'mitt'
import App from './App.vue'
const app = createApp(App)
app.config.globalProperties.$bus = mitt()
app.mount('#app')
「发送事件的组件:」
<script setup>
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
const sendMessage = () => {
proxy.$bus.emit('myEvent', '你好,同学')
}
</script>
「接收事件的组件:」
<script setup>
import { onMounted, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
onMounted(() => {
proxy.$bus.on('myEvent', (message) => {
console.log(message) // 输出: "你好,同学"
})
})
</script>
还有另外的写法
新建文件:src\utils\emitter.ts
// 引入mitt
import mitt from "mitt";
// 创建emitter
const emitter = mitt()
/*
// 绑定事件
emitter.on('abc',(value)=>{
console.log('abc事件被触发',value)
})
emitter.on('xyz',(value)=>{
console.log('xyz事件被触发',value)
})
setInterval(() => {
// 触发事件
emitter.emit('abc',666)
emitter.emit('xyz',777)
}, 1000);
setTimeout(() => {
// 清理事件
emitter.all.clear()
}, 3000);
*/
// 创建并暴露mitt
export default emitter
接收数据的组件中:绑定事件、同时在销毁前解绑事件:
import emitter from "@/utils/emitter";
import { onUnmounted } from "vue";
// 绑定事件
emitter.on('send-info',(value)=>{
console.log('send-info事件被触发',value)
})
onUnmounted(()=>{
// 解绑事件
emitter.off('send-info')
})
【第三步】:提供数据的组件,在合适的时候触发事件
import emitter from "@/utils/emitter";
function sendInfo(){
// 触发事件
emitter.emit('send-info',info.value)
}
4. 透传 Attributes ($attrs)
$attrs 包含了父组件传递给子组件的所有属性,除了那些已经被 props 或 emits 声明的。
<template>
<child name="小豆" age="18" hobby="看书"></child>
</template>
「子组件:」
<script setup>
import { useAttrs } from 'vue'
defineProps(['name'])
const attrs = useAttrs()
console.log(attrs) // { age: "18", hobby: "看书" }
</script>
<template>
<div>
{{ name }}
</div>
</template>
5. 模板引用 (Refs)
通过 ref,父组件可以直接访问子组件的属性和方法。
「父组件:」
<template>
<child ref="childRef"></child>
<button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
const callChildMethod = () => {
childRef.value.someMethod()
}
</script>
「子组件:」
<script setup>
import { defineExpose } from 'vue'
const someMethod = () => {
console.log('子组件方法被调用了')
}
defineExpose({
someMethod,
})
</script>
6. 双向绑定 (v-model)
v-model 提供了一种简洁的方式来实现父子组件之间的双向数据绑定。
「父组件:」
<template>
<child v-model:name="name"></child>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const name = ref('小明')
</script>
「子组件:」
<template>
<input :value="name" @input="updateName" />
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps(['name'])
const emit = defineEmits(['update:name'])
const updateName = (e) => {
emit('update:name', e.target.value)
}
</script>
7. 依赖注入 (Provide/Inject)
provide 和 inject 允许祖先组件向所有子孙组件传递数据,而不需要通过每一层组件手动传递。
「祖先组件:」
<script setup>
import { provide, ref } from 'vue'
const themeColor = ref('blue')
provide('theme', themeColor)
</script>
「子孙组件:」
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
console.log(theme.value) // 'blue'
</script>
8. 路由传参
Vue Router 提供了多种方式在路由之间传递参数。
「通过 query 传参:」
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({ path: '/user', query: { id: 123 } })
// 在目标组件中
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query.id) // 123
「通过 params 传参:」
同上:query=>params
「通过 router-link 里面的 to 传参:」
<router-link to="/father/son/传入的参数">父亲组件<router-link>
<router-link to="path: '/father/son', query: { title: title }">父亲组<router-link>
9. Vuex 状态管理
Vuex 是 Vue 的官方状态管理库,适用于大型应用。
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++
},
},
})
组件中使用
import { useStore } from 'vuex'
const store = useStore()
console.log(store.state.count)
store.commit('increment')
10. Pinia 状态管理
Pinia 是新一代的 Vue 状态管理库,提供更简单的 API 和更好的 TypeScript 支持。
store.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++
},
},
})
组件中使用
import { useCounterStore } from '@/store'
const counter = useCounterStore()
console.log(counter.count)
counter.increment()
11. 浏览器存储
localStorage 和 sessionStorage 可以用于在不同页面或组件之间共享数据。
// localStorage存储数据
localStorage.setItem('user', JSON.stringify({ name: '青阳子', age: 38 }))
// localStorage读取数据
const user = JSON.parse(localStorage.getItem('user'))
// sessionStorage 存储数据
sessionStorage .setItem('user', JSON.stringify({ name: '青阳子', age: 38 }))
// sessionStorage 读取数据
const user = JSON.parse(sessionStorage .getItem('user'))
12. Window 对象
// 设置全局数据
window.globalData = { message: '全局消息' }
// 在任何地方使用
console.log(window.globalData.message)
13. 全局属性
Vue 3 提供了 app.config.globalProperties 来替代 Vue 2 中的 Vue.prototype,用于添加全局可用的属性。
// main.js
// main.js
const app = createApp(App)
app.config.globalProperties.$http = axios
// 在组件中使用
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
proxy.$http.get('/api/data')
总结:
总结这 13 种方法涵盖了 Vue 3 中几乎所有的组件通信场景。根据你的具体需求和应用规模,选择最合适的通信方式。好的组件设计能够简化通信,提高代码的可维护性。

2万+

被折叠的 条评论
为什么被折叠?



