Vue3 组件通信

130 阅读1分钟

一句话总结:Vue3组件通信主要通过Props、Emits、v-model、Provide & Inject、全局状态管理(如Pinia或Vuex)、$refs以及组合式API等方式实现。

props

父组件给子组件传递数据

父组件

<template>
  <div>
    <h2>父组件</h2>
    <Child :car="car" />
  </div>  
</template>

<script setup lang="ts">
  import Child from './Child.vue'
  import {ref} from 'vue'
  let car = ref('雅迪')
</script>

子组件

<template>
  <div>
    <h2>子组件</h2>
    <div>父组件传递的数据: {{ car }}</div>
  </div>
</template>

<script setup lang="ts">
defineProps(["car"]);
</script>
子组件给父组件传递数据

父组件传递一个函数

<template>
  <div>
    <h2>父组件</h2>
    <Child :sendToy="getToy" />
  </div>  
</template>

<script setup lang="ts">
  import Child from './Child.vue'
  import {ref} from 'vue'
  function getToy(value:string) {
    console.log(value);
  }
</script>

子组件调用函数并传递数据

<template>
  <div>
    <h2>子组件</h2>
    <button @click="sendToy(toy)">给父组件传递数据</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
defineProps(["sendToy"]);
let toy = ref("阿童木");
</script>
父组件给孙组件传递数据

父组件传递数据

<template>
  <div>
    <h2>父组件</h2>
    <Child :car="car" />
  </div>  
</template>

<script setup lang="ts">
  import Child from './Child.vue'
  import {ref} from 'vue'

  let car = ref("雅迪")
</script>

子组件不接收,就会到$attrs里面,然后传递给孙组件

<template>
  <div>
    <h2>子组件</h2>
    <Grandson :car="$attrs" />
  </div>
</template>

<script setup lang="ts">
import Grandson from './Grandson.vue';
</script>

孙组件接收

<template>
  <div>
    <h2>孙组件</h2>
    <div>父传递的数据:{{ car }}</div>
  </div>
</template>
 
<script setup lang="ts">
defineProps(['car'])
</script>

自定义事件

给子组件绑定事件

<template>
  <div>
    <h2>父组件</h2>
    <Child @get-toy="getToy" />
  </div>  
</template>

<script setup lang="ts">
  import Child from './Child.vue'
  import {ref} from 'vue'

  let car = ref("雅迪")
  function getToy(value) {
    console.log(value);
    
  }
</script>

子组件声明并调用事件

<template>
  <div>
    <h2>子组件</h2>
    <button @click="setToy">给父组件传递数据</button>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue'
let toy = ref("阿童木")
const emit = defineEmits(["get-toy"])
function setToy() {
  emit("get-toy", toy)
}
</script>

mitt

安装mitt:npm i mitt

utils/emitter.ts
// 引入mitt
import mitt from 'mitt'
// 暴露mitt
export default mitt()

父组件

<template>
  <div>
    <h2>父组件</h2>
    <button @click="sendData">给子组件发送数据</button>
    <Child />
  </div>
</template>

<script setup lang="ts">
  import Child from './Child.vue';
  import {ref} from 'vue'
  import emitter from '@/utils/emitter';
  let car = ref("雅迪")
  function sendData() {
    // 发送事件
    emitter.emit('send-data', car)
  }
</script>

子组件

<template>
  <div>
    <h2>子组件</h2>
    <div>父组件给的数据: {{ car }}</div>
  </div>
</template>

<script setup lang="ts">
import {ref, onUnmounted} from 'vue'
import emitter from '@/utils/emitter';
let car = ref('')
// 触发事件
emitter.on("send-data", (value:any)=>{
  car.value = value
})
// 解绑事件
onUnmounted(()=>{
  emitter.off("send-data")
})
</script>

v-model

在组件上面使用v-model,ui组件常用

<template>
  <div>
    <FatherInput v-model="car" />
  </div>
</template>

<script setup lang="ts">
  import FatherInput from './FatherInput.vue';
  import {ref} from 'vue'
  let car = ref("雅迪")
</script>

本质写法

// 父组件
<template>
  <div>
    <!-- <FatherInput v-model="car" /> -->
    <FatherInput :modelValue="car" @updata:modelValue="car = $event" />
  </div>
</template>

<script setup lang="ts">
  import FatherInput from './FatherInput.vue';
  import {ref} from 'vue'
  let car = ref("雅迪")
</script>

// 子组件
<template>
  <input
    type="text"
    :value="modelValue"
    @input="emit('updata:modelValue',(<HTMLInputElement>$event.target).value)"
  />
</template>

<script lang="ts" setup>
defineProps(["modelValue"]);
const emit = defineEmits(["updata:modelValue"]);
</script>

provide-inject

祖孙传参

// 父组件
<template>
  <div>
    <h2>父组件</h2>
    <Child />
  </div>
</template>

<script setup lang="ts">
  import Child from './Child.vue';
  import {ref, provide} from 'vue'
  let car = ref("雅迪")
  // 向后代提供数据
  provide("car", car)
</script>

// 孙组件
<template>
  <div>
    <h4>孙组件</h4>
    {{ car }}
  </div>
</template>

<script setup lang="ts">
import {inject} from 'vue'
// 注入数据
let car = inject('car', "默认值")
</script>