Skip to content

组件通信

1. 父子组件通信

1.1 父组件向子组件传递数据

vue
<!-- 父组件 -->
<template>
  <child-component 
    :message="message"
    :user="user"
    v-bind="$attrs"
  ></child-component>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello',
      user: { name: 'John' }
    }
  }
}
</script>

<!-- 子组件 -->
<script>
export default {
  props: {
    message: String,
    user: {
      type: Object,
      required: true
    }
  }
}
</script>

1.2 子组件向父组件传递数据

vue
<!-- 子组件 -->
<template>
  <button @click="handleClick">发送数据</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$emit('update', { data: 'some data' })
    }
  }
}
</script>

<!-- 父组件 -->
<template>
  <child-component @update="handleUpdate"></child-component>
</template>

<script>
export default {
  methods: {
    handleUpdate(data) {
      console.log('从子组件接收到数据:', data)
    }
  }
}
</script>

1.3 兄弟组件通信

1.3.1 通过父组件中转

vue
<!-- 父组件 -->
<template>
  <div>
    <component-a @message="handleMessage"></component-a>
    <component-b :message="message"></component-b>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: ''
    }
  },
  methods: {
    handleMessage(msg) {
      this.message = msg
    }
  }
}
</script>

1.3.2 事件总线(EventBus)

js
// eventBus.js
import Vue from 'vue'
export const eventBus = new Vue()

// 组件A
methods: {
  sendMessage() {
    eventBus.$emit('custom-event', data)
  }
}

// 组件B
created() {
  eventBus.$on('custom-event', data => {
    console.log(data)
  })
}

2. 跨层级组件通信

2.1 Provide/Inject

js
// 祖先组件
export default {
  provide() {
    return {
      theme: 'dark',
      user: this.user
    }
  },
  data() {
    return {
      user: { name: 'John' }
    }
  }
}

// 后代组件
export default {
  inject: ['theme', 'user']
}

2.2 Vuex状态管理

js
// store.js
import Vuex from 'vuex'

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  }
})

// 组件中使用
export default {
  computed: {
    count() {
      return this.$store.state.count
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment')
    }
  }
}

3. Vue3的组件通信

3.1 组合式API通信

js
// 父组件
import { ref, provide } from 'vue'

export default {
  setup() {
    const message = ref('Hello')
    provide('message', message)
    
    return { message }
  }
}

// 子组件
import { inject } from 'vue'

export default {
  setup() {
    const message = inject('message')
    return { message }
  }
}

3.2 Props和Emits声明

js
// Vue3组件
export default {
  props: {
    message: String
  },
  emits: ['update'],
  setup(props, { emit }) {
    const handleClick = () => {
      emit('update', 'new value')
    }
    
    return { handleClick }
  }
}

4. 进阶通信方式

4.1 $refs引用

vue
<template>
  <child-component ref="childRef"></child-component>
</template>

<script>
export default {
  mounted() {
    // 访问子组件实例
    this.$refs.childRef.someMethod()
  }
}
</script>

4.2 $parent和$root

js
// 子组件中访问父组件
methods: {
  accessParent() {
    console.log(this.$parent.parentData)
  }
}

4.3 插槽通信

vue
<!-- 父组件 -->
<template>
  <child-component>
    <template v-slot:default="slotProps">
      {{ slotProps.text }}
    </template>
  </child-component>
</template>

<!-- 子组件 -->
<template>
  <div>
    <slot :text="message"></slot>
  </div>
</template>

5. 最佳实践

5.1 通信方式选择原则

  1. 父子组件:优先使用props/emit
  2. 兄弟组件:考虑事件总线或状态管理
  3. 跨层级组件:使用provide/inject或状态管理
  4. 全局状态:使用Vuex/Pinia

5.2 性能优化

  1. 避免过度使用事件总线
  2. 合理使用计算属性缓存
  3. 及时销毁事件监听
  4. 避免深层组件嵌套

5.3 调试技巧

  1. Vue Devtools监控数据流
  2. 使用事件追踪
  3. 控制台调试
  4. 性能分析