vue3组件间通信方式

553 阅读2分钟

父子通信

父组件主动向子组件传递数据

defineProps

父组件使用v-bind绑定需要传递的数据,子组件从vue中使用defineProps,实例化对象进行接受

父组件

<template>
  <Child :msg="parentMsg" />
</template>

<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const parentMsg = ref('im parent')

</script>

<style lang="css" scoped></style>

子组件

<template>
  <div>
    {{ props.msg }}
  </div>

</template>

<script setup>

const props = defineProps({
  msg: {
    type: String
  }
})

</script>

<style lang="scss" scoped></style>

子父通信

子组件主动向父组件传递数据

发布订阅方式

采用了发布订阅的方式实现

首先子组件定义好一个事件

const emit = defineEmits(['addChild'])

定义好后,将该事件发布出去,我在这采用了一个点击事件触发发布时间的行为

const add = () => {
  emit('addChild', childMsg.value)
}

最后在父组件对该事件进行订阅,订阅的事件名一定要和子组件发布的事件名一致,里面会传递一个参数,该参数就是子组件传递的数据。

<Child @addChild="handle" />

具体代码如下

child

<template>
  <div>
    <button @click="add">发送给父组件</button>
  </div>

</template>

<script setup>
import { ref } from 'vue';

const childMsg = ref('im child')
const emit = defineEmits(['addChild'])
const add = () => {
  emit('addChild', childMsg.value)
}

</script>

<style lang="scss" scoped></style>

parent

<template>

  <Child @addChild="handle" />
  {{ msg }}
</template>

<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const msg = ref('')
const handle = (e) => {
  msg.value = e
}

</script>

<style lang="css" scoped></style>

defineExpose+ref

使用了defineExpose主动对外暴露,想要暴露的数据

defineExpose({
  msg
})

父组件通过ref定义子组件的dom元素,从而从dom元素中拿到挂载在该对象上的属性。注意由于这个过程是异步的第一次访问时这个值是不存在,所以需要在访问之前判断存不存否则会执行会出错。

<Child ref="refChild" />
  {{ refChild?.msg }}

全部代码如下

child

<template>
  <div>

  </div>

</template>

<script setup>
import { ref } from 'vue';

const msg = ref('im child')
defineExpose({
  msg
})

</script>

<style lang="scss" scoped></style>

parent

<template>
  <Child ref="refChild" />
  {{ refChild?.msg }}
</template>

<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const refChild = ref(null)
</script>

<style lang="css" scoped></style>

子父组件的双向数据绑定

双向数据绑定,实现vue3数据不再是单向流通的

v-model

双向数据绑定主要使用了v-model

首先在父组件上选择好绑定的数据。

<Child v-model:msg="msg" />

对于子组件来说分两步走 第一点,子组件得到来自父组件传递的数据,使用defineProps

第二点,子组件使用defineEmits,发布事件

const props = defineProps({
  msg: {
    type: String,
    required: true
  }
})
const emits = defineEmits(['update:msg'])

具体代码如下

parent

<template>
  {{ msg }}
  <Child v-model:msg="msg" />
</template>

<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const msg = ref('im parent')
</script>

<style lang="css" scoped></style>

child

<template>
  <div>
    <input type="text" :value="props.msg" @input="changeMsg">
  </div>
</template>

<script setup>
const props = defineProps({
  msg: {
    type: String,
    required: true
  }
})
const emits = defineEmits(['update:msg'])

const changeMsg = (e) => {
  emits('update:msg', e.target.value)
}
</script>

<style lang="scss" scoped></style>

子孙通信

主要设计目的是用于祖先组件向后代组件单向传递数据,但如果有需求让后代组件向祖先组件传递数据

provide/inject

首先在父组件中使用provide抛出想要传递的数据

provide('parentMsg', msg)

在孙组件中使用inject接受即可

const msg = inject('parentMsg')

具体代码 parent

<template>
  <Child />
</template>

<script setup>
import Child from './child.vue';
import { provide, ref } from 'vue';
const msg = ref('im parent')
provide('parentMsg', msg)
</script>

<style lang="css" scoped></style>

grandson

<template>
  <div>
    {{ msg }}
  </div>
</template>

<script setup>
import { inject } from 'vue';

const msg = inject('parentMsg')
</script>

<style lang="scss" scoped></style>