likes
comments
collection
share

Vue3 几种组件间通信方法

作者站长头像
站长
· 阅读数 4

父子通讯

父传子

父向子组件传参有两种形式:

  • 单项传递 父组件传递给子组件使用,子组件只有使用权
  • 双向传递 父组件和子组件共用数据,均可修改。

单项传递

子组件通过defineProps来接收参数

defineProps的两种写法:

  • 数组 可直接接收传递的参数
  • 对象 可限制传递参数的类型,是否必填,默认值等
// app.vue
<template>
    <Child :msg="msg" />
</template>
<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const msg = ref('hello')

</script>

<style scoped>

</style>
// Child.vue
<template>
  <div>{{ msg }}</div>
</template>
<script setup>
import { ref } from 'vue'
// const props = defineProps(['msg'])
const props = defineProps({
  msg: {
    type: String, // 类型
    required: true, // 是否必填
    default() { // 默认值
      return 'hi'
    }
  }
})
const { msg } = props

</script>
<style scoped>

</style>

注意:使用结构的写法会丢失响应性 推荐使用torefs()转为响应式数据,示例 const { msg } = toRefs(props)

双向传递

defineModel它的存在解决了单项绑定的尴尬场景,在最新的Vue3.4版本中推荐使用

// app.vue
<template>
  <Child v-model:msg="msg" />
</template>
<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const msg = ref('hello')

</script>

<style scoped>

</style>
// Child.vue
<template>
  <div>{{ msg }}</div>
</template>
<script setup>
import { ref, defineModel } from 'vue'
// const msg = defineModel('msg')
const msg = defineModel('msg', {
  type: String, // 类型
  // required: true, 是否必填
  default() { // 默认值
    return 'hi'
  }
})

</script>
<style scoped>

</style>

子传父

defineEmits 接收父组件定义的事件,通过第二个参数传递数据

// app.vue
<template>
  <h3>{{ flag }}</h3>
  <Child @getValue="getValue" />
</template>
<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const flag = ref('')

const getValue = (value) => {
  flag.value = value
}

</script>

<style scoped>

</style>
// Child.vue
<template>
  <button @click="handleClick">button</button>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const flag = ref('你好!')
const $emit = defineEmits(['getValue'])
const handleClick = () => {
  $emit('getValue', flag.value)
}

</script>
<style scoped>

</style>

父组件调用子组件属性

这种父子组件的通讯方式也经常用的到,子组件利用defineExpose 暴露出去属性,父组件通过ref拿到子组件实例使用子组件的属性

// app.vue
<template>
  <Child ref="child"/>
  <button @click="getChild">app-button</button>
</template>
<script setup>
import Child from './components/Child.vue'
import { ref } from 'vue'
const child = ref()

const getChild = () => {
  console.log(child.value.flag)
  child.value.handleClick()
}

</script>

<style scoped>

</style>
// Child.vue
<template>
  <button @click="handleClick">button</button>
</template>
<script setup>
import { ref, defineExpose} from 'vue'
const flag = ref('你好!')
const handleClick = () => {
  console.log(flag.value)
}
// 暴露属性
defineExpose({
  flag,
  handleClick
})
</script>
<style scoped>

</style>

爷孙通讯

当组件的层次结构比较深时,使用上面几种方案就没什么作用了,Vue中Provide / Inject的存在就是解决这个问题的。

Provide Inject是什么?

父组件中提供数据,并在子组件中注入这些数据,从而实现了组件之间的数据传递。简单来说就是父组件向子组件传值的一个方式

注意:provide 和 inject 绑定并不是可响应的

Vue3 几种组件间通信方法

// app.vue
<template>
  <Child />
</template>
<script setup>
import Child from './components/Child.vue'
import { ref, provide } from 'vue'
provide('app', '你好!')

</script>

<style scoped>

</style>

// Child.vue
<template>
  <DeepChild />
</template>
<script setup>
import DeepChild from './DeepChild.vue'
import { ref} from 'vue'

</script>
<style scoped>

</style>

// DeepChild.vue
<template>
    <h3>{{ msg }}</h3>
  </template>
  <script setup>
  import { inject } from 'vue'
  const msg = inject('app')
  </script>
  <style scoped>
  
  </style>
  

总的来说,provideinject 是一种强大的依赖注入机制,特别适用于大型和复杂的应用程序,以提高代码的可维护性、可测试性和可扩展性。但在小型应用中,可能会增加一些复杂性,需要谨慎使用。在使用时,需要根据具体的场景和需求来判断是否使用这些特性,在组件封装过程中,也可以根据情况进行使用。

以上就是我经常用的几种组件间的通讯方法,通过简单的示例分别演示了使用方法,希望对大家有所帮助。