vue3组件通信

在 Vue 3 中,组件之间的通信是构建应用程序的关键。本文将介绍 13 种不同的组件通信方法,从最简单到最复杂,帮助你选择最适合你需求的方式。

  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>
    import { defineProps } from 'vue'
    
    const props = defineProps({
      name: {
        type: String,
        default: '',
      },
    })
    </script>
    
  2. 子组件向父组件传递数据 (Emit)

    子组件可以通过触发事件的方式向父组件传递数据。

    「子组件:」

    <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>
    

    「父组件:」

    <template>
      <child @greet="handleGreet"></child>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import Child from './Child.vue'
    
    const handleGreet = (message) => {
      console.log(message) // 输出: "来自子组件的问候"
    }
    </script>
    
  3. 兄弟组件通信 (Mitt)

    对于兄弟组件之间的通信,我们可以使用第三方库 mitt 来实现一个简单的事件总线。

    首先,安装 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>
    
  4. 透传 Attributes ($attrs)

    $attrs 包含了父组件传递给子组件的所有属性,除了那些已经被 props 或 emits 声明的。

    「父组件:」

    <template>
      <child name="小明" age="18" hobby="篮球"></child>
    </template>
    

    「子组件:」

    <script setup>
    import { useAttrs } from 'vue'
    
    const attrs = useAttrs()
    console.log(attrs) // { age: "18", hobby: "篮球" }
    </script>
    
  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
    
  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 支持。

    // stores/counter.js
    import { defineStore } from 'pinia'
    
    export const useCounterStore = defineStore('counter', {
      state: () => ({ count: 0 }),
      actions: {
        increment() {
          this.count++
        },
      },
    })
    
    // 在组件中使用
    import { useCounterStore } from '@/stores/counter'
    
    const counter = useCounterStore()
    console.log(counter.count)
    counter.increment()
    
  11. 浏览器存储

    localStorage 和 sessionStorage 可以用于在不同页面或组件之间共享数据。

    // 存储数据
    localStorage.setItem('user', JSON.stringify({ name: '小明', age: 18 }))
    
    // 读取数据
    const user = JSON.parse(localStorage.getItem('user'))
    
  12. Window 对象

    虽然不推荐,但在某些场景下,可以使用 window 对象在全局范围内共享数据。

    // 设置全局数据
    window.globalData = { message: '全局消息' }
    
    // 在任何地方使用
    console.log(window.globalData.message)
    
  13. 全局属性

    Vue 3 提供了 app.config.globalProperties 来替代 Vue 2 中的 Vue.prototype,用于添加全局可用的属性。

    // 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 中几乎所有的组件通信场景。根据你的具体需求和应用规模,选择最合适的通信方式。记住,好的组件设计能够简化通信,提高代码的可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值