Vue 的父子传输数据全解析

Vue 的父子传输数据全解析

常见的父子传输数据的操作,基于 vue3.0,不包括 store、localstorage 等对象的使用。

文中代码地址

父传子

1.通过 props 传参

父组件:

<template>
	<Child1 :data="data"></Child1>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import Child1 from './Child1.vue'
export default defineComponent({
	components: {
		Child1
	},
	setup() {
		return {
			data: '测试'
		}
	}
})
</script>

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

子组件:

<template>
	<div>
		{{ data }}
	</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
	props: {
		data: {
			type: String,
			default: () => ''
		}
	},
	setup() {
		return {}
	}
})
</script>

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

2.inject and provide

父组件:

<template>
	<div>
		<Child2></Child2>
	</div>
</template>

<script lang="ts">
import { defineComponent, provide, ref } from 'vue'
import Child2 from './Child2.vue'
import { injectSymbol } from './Symbol'

export default defineComponent({
	components: {
		Child2
	},
	setup() {
		const data = ref('测试2')
		provide(injectSymbol, data)
		return {}
	}
})
</script>

<style scoped></style>

子组件:

<template>
	<div>
		{{ data }}
	</div>
</template>

<script lang="ts">
import { defineComponent, inject } from 'vue'
import { injectSymbol } from './Symbol'

export default defineComponent({
	setup() {
		const data = inject(injectSymbol)

		return {
			data
		}
	}
})
</script>

<style scoped></style>

[!TIP] inject 备注
inject 有三个参数,依次为:

1、key or symbol

2、默认值

3、是否使用工厂函数

以下是一个工厂函数的应用场景:

import { inject } from 'vue';

export default {
  setup() {
    const config = inject('config', () => ({ theme: 'default', fontSize: 14 }), true);
    // 子组件可以修改自己的 config 而不会影响其他组件
    config.value.theme = 'dark';
    // 使用 config...
    return { config };
  }
}

3.slot 插槽

父组件:

<template>
	<div>
		<Child3>
			<template #main>
				{{ data }}
			</template>
		</Child3>
	</div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import Child3 from './Child3.vue'

export default defineComponent({
	components: {
		Child3
	},
	setup() {
		const data = ref('测试3')

		return {
			data
		}
	}
})
</script>

<style scoped></style>

子组件:

<template>
	<div>
		<slot name="main"></slot>
	</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({

	setup() {
		return {}
	}
})
</script>

<style scoped></style>

4.使用 ref 获取组件

父组件:

<template>
	<div>
		<Child4 ref="child"></Child4>
	</div>
</template>

<script lang="ts">
import { defineComponent, useTemplateRef, onMounted } from 'vue'
import Child4 from './Child4.vue'

export default defineComponent({
	components: {
		Child4
	},
	setup() {
		const child: any = useTemplateRef('child')
		onMounted(() => {
			child.value.data = '测试4'
		})
		return {}
	}
})
</script>

<style scoped></style>

子组件:

<template>
	<div>
		{{ data }}
	</div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
	setup() {
		const data = ref('')

		return {
			data
		}
	}
})
</script>

<style scoped></style>

PixPin_2025-05-24_17-19-13.png

子传父

1.ref

父组件通过 ref 直接获取子组件的实例,本质上操作的同一份数据,既可以理解为父传子,也可以理解为子传父。

2.emit

父组件:

<template>
	{{ data }}
	<Child1 :data="data" @update-data="updateData"></Child1>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import Child1 from './Child1.vue'
export default defineComponent({
	components: {
		Child1
	},
	setup() {
		const data = ref('测试1')
		const updateData = (val: any) => {
			data.value = val
		}
		return {
			data,
			updateData
		}
	}
})
</script>

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

子组件:

<template>
	<div>
		{{ data }}
		<button @click="updateData('修改后的测试1')">修改</button>
	</div>
</template>

<script lang="ts">
import { defineComponent, defineEmits } from 'vue'
export default defineComponent({
	props: {
		data: {
			type: String,
			default: () => ''
		}
	},
	setup(props, { emit }) {
		const updateData = (val: any) => {
			emit('update-data', val)
		}
		return {
			updateData
		}
	}
})
</script>

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

3.v-model

双向绑定,其实是 props 和 emit 加起来的语法糖。

父组件:

<template>
	<div>
		{{ data }}
		<Child5 v-model="data"></Child5>
	</div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import Child5 from './Child5.vue'

export default defineComponent({
	components: {
		Child5
	},
	setup() {
		const data = ref('测试5')

		return {
			data
		}
	}
})
</script>

<style scoped></style>

子组件:

<template>
	<div>
		{{ modelValue }}
		<button @click="change('修改后的测试5')">修改</button>
	</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
	props: {
		modelValue: {
			type: String,
			default: () => ''
		}
	},
	setup(props, { emit }) {
		const change = (newValue: string) => {
			emit('update:modelValue', newValue)
		}

		return {
			change
		}
	}
})
</script>

<style scoped></style>

4.共享 reactive

reactive 在传输的时候是公用的同一个对象。

而 ref 则会被 Vue 会自动“解包” ref,子组件接收到的是它的 .value 值,如果要实现双向,使用 Ref 声明对象类型。

父组件:

<template>
  <div>
    <h2>父组件</h2>
    <p>计数器:{{ sharedState.count }}</p>
    <Child :shared-state="sharedState" />
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import Child from './Child.vue'

// 创建 reactive 对象
const sharedState = reactive({
  count: 0
})
</script>

子组件:

<template>
  <div>
    <h3>子组件</h3>
    <button @click="sharedState.count++">增加计数器</button>
  </div>
</template>

<script setup>
defineProps({
  sharedState: Object
})
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城南顾北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值