Vue3 几种组件间通信方法
父子通讯
父传子
父向子组件传参有两种形式:
- 单项传递 父组件传递给子组件使用,子组件只有使用权
- 双向传递 父组件和子组件共用数据,均可修改。
单项传递
子组件通过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 绑定并不是可响应的
// 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>
总的来说,provide
和 inject
是一种强大的依赖注入机制,特别适用于大型和复杂的应用程序,以提高代码的可维护性、可测试性和可扩展性。但在小型应用中,可能会增加一些复杂性,需要谨慎使用。在使用时,需要根据具体的场景和需求来判断是否使用这些特性,在组件封装过程中,也可以根据情况进行使用。
以上就是我经常用的几种组件间的通讯方法,通过简单的示例分别演示了使用方法,希望对大家有所帮助。
转载自:https://juejin.cn/post/7361278864087859252