Vue3 组件通信

Vue3 组件通信

1.【props】父传子

核心概念:父组件通过属性传递数据给子组件

<!-- 父组件 -->
<template>
  <Child :car="car" :getToy="getToy"/>
</template>

<script setup>
import { ref } from "vue"
const car = ref('奔驰')

function getToy(value) {
  console.log('收到子组件的玩具:', value)
}
</script>

<!-- 子组件 -->
<script setup>
// 接收props
defineProps(['car','getToy'])
</script>

使用场景

  • 父组件向子组件传递数据
  • 子组件向父组件传递数据(通过传递函数)

2.【自定义事件】子传父

核心概念:子组件通过事件向父组件传递数据

<!-- 父组件监听事件 -->
<template>
  <Child @send-toy="handleToy"/>
</template>

<script setup>
const handleToy = (toy) => {
  console.log('收到玩具:', toy)
}
</script>

<!-- 子组件触发事件 -->
<script setup>
const emit = defineEmits(['send-toy'])

const sendData = () => {
  emit('send-toy', '奥特曼')
}
</script>

3.【mitt】任意组件通信

核心概念:全局事件总线,任意组件间通信

// utils/emitter.ts
import mitt from "mitt"
const emitter = mitt()
export default emitter

// 组件A - 发送事件
import emitter from "@/utils/emitter"
emitter.emit('send-data', data)

// 组件B - 接收事件
import emitter from "@/utils/emitter"
emitter.on('send-data', (data) => {
  console.log('收到数据:', data)
})

4.【v-model】双向绑定

核心概念:简化父子组件双向数据绑定

<!-- 父组件 -->
<template>
  <CustomInput v-model="username"/>
</template>

<!-- 子组件 -->
<template>
  <input 
    :value="modelValue" 
    @input="$emit('update:modelValue', $event.target.value)"
  >
</template>

<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

5.【$attrs】祖传孙

核心概念:父组件属性自动传递给子组件

<!-- 父组件 -->
<template>
	<Child :a="a" :b="b" :c="c"/>
</template>

<!-- 子组件直接传递 -->
<template>
	<GrandChild v-bind="$attrs"/>
</template>

<!-- 孙组件接收 -->
<script setup lang="ts" name="GrandChild">
defineProps(['a','b','c','d','x','y','updateA'])
</script>

6.【$refs、$parent】直接访问

核心概念:直接访问组件实例 $refs、

<script setup>
// 父组件访问子组件
const childRef = ref()
childRef.value.someMethod()

// 子组件访问父组件
const parent = getCurrentInstance().parent
</script>

7.【provide/inject】依赖注入

核心概念:祖先组件提供数据,后代组件注入使用

<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue'

const money = ref(100)
provide('money', money)
</script>

<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'

const money = inject('money')
</script>

8.【slot】插槽

核心概念:父组件向子组件传递模板内容

8.1.默认插槽

父组件中:
        <Category title="今日热门游戏">
          <ul>
            <li v-for="g in games" :key="g.id">{{ g.name }}</li>
          </ul>
        </Category>
子组件中:
        <template>
          <div class="item">
            <h3>{{ title }}</h3>
            <!-- 默认插槽 -->
            <slot></slot>
          </div>
        </template>

8.2.具名插槽

父组件中:
        <Category title="今日热门游戏">
          <template v-slot:s1>
            <ul>
              <li v-for="g in games" :key="g.id">{{ g.name }}</li>
            </ul>
          </template>
          <template #s2>
            <a href="">更多</a>
          </template>
        </Category>
子组件中:
        <template>
          <div class="item">
            <h3>{{ title }}</h3>
            <slot name="s1"></slot>
            <slot name="s2"></slot>
          </div>
        </template>

8.3.作用域插槽

父组件中:
      <Game v-slot="params">
      <!-- <Game v-slot:default="params"> -->
      <!-- <Game #default="params"> -->
        <ul>
          <li v-for="g in params.games" :key="g.id">{{ g.name }}</li>
        </ul>
      </Game>

子组件中:
      <template>
        <div class="category">
          <h2>今日游戏榜单</h2>
          <slot :games="games" a="哈哈"></slot>
        </div>
      </template>

      <script setup lang="ts" name="Category">
        import {reactive} from 'vue'
        let games = reactive([
          {id:'asgdytsa01',name:'英雄联盟'},
          {id:'asgdytsa02',name:'王者荣耀'},
          {id:'asgdytsa03',name:'红色警戒'},
          {id:'asgdytsa04',name:'斗罗大陆'}
        ])
      </script>

9.【Pinia】状态管理

9.1.为什么需要 Pinia?

问题:当多个组件需要共享相同数据时,props 逐层传递太繁琐
解决方案:Pinia 提供全局状态管理,任何组件都可以直接访问

9.2.三大核心概念

9.2.1.State - 存储数据
export const useStore = defineStore('store', {
  state: () => ({
    count: 0,
    user: null
  })
})
9.2.2.Getters - 计算属性
getters: {
  doubleCount: (state) => state.count * 2
}
9.2.3. Actions - 操作方法
actions: {
  increment() {
    this.count++
  }
}

10.使用场景对比

通信方式适用场景数据流向
props父子组件简单数据传递父 → 子
emit子组件向父组件发送消息子 → 父
mitt任意无关组件通信任意方向
v-model表单组件双向绑定父子双向
provide/inject深层嵌套组件传值祖先 → 后代
$refs/$parent父(子)组件访问子(父)组件实例父 → 子(子 → 父)
slot父组件向子组件传递模板父 → 子
Pinia多个组件共享复杂状态全局共享

**选择建议 **

  1. 简单父子通信 → props + emit
  2. 无关组件通信 → mitt
  3. 深层嵌套传值 → provide/inject
  4. 复杂状态共享 → Pinia
  5. 表单组件 → v-model
  6. 传递模板内容 → slot
  7. 直接访问组件实例 → $refs、$parent

记住:不要为了用 Pinia 而用 Pinia,简单的组件通信用 props 和 emit 就足够了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值