目录
在 Vue 开发中,组件之间的传值是非常重要的环节。本文将详细介绍 Vue2 中的组件传值方式,并结合 Vue3 的情况进行分析,同时给出相应的代码示例。
一、Vue2 组件传值方式
(一)父传子
- 绑定形式传值
- 在父组件中,通过单向绑定的方式将数据传递给子组件。例如:
<template>
<div>
<list :str1="str1"></list>
</div>
</template>
<script>
import list from './list.vue';
export default {
components: { list },
data() {
return {
str1: 'home 的数据',
};
},
};
</script>
- 在子组件中,通过
props
接收父组件传递过来的数据。例如:
<template>
<div>{{ str1 }}</div>
</template>
<script>
export default {
props: {
str1: {
type: String,
default: '',
},
},
};
</script>
- 这种方式的优点是父传子很方便,但缺点是无法直接将数据传递给孙子辈组件,需要一级一级传递。
- 子组件直接使用父组件数据
- 在子组件中,可以通过
this.$parent
来获取父组件的数据。例如:
- 在子组件中,可以通过
<template>
<div>{{ this.$parent.str1 }}</div>
</template>
<script>
export default {
mounted() {
console.log(this.$parent.str1);
},
};
</script>
- 这种方式子组件可以直接拿到父组件的数据,但与传统的传值方式不同,它不是通过父组件主动传递数据给子组件。而且这种方式写死了数据的获取路径,不便于维护。同时,子组件可以直接修改父组件的数据,这可能会导致数据的不可控性。
(二)子传父
- 自定义事件传值
- 在子组件中,定义一个自定义事件,并在触发事件时将数据传递给父组件。例如:
<template>
<div>
<button @click="sendDataToParent">点击传值给父组件</button>
</div>
</template>
<script>
export default {
data() {
return {
str2: 'list 组件的数据',
};
},
methods: {
sendDataToParent() {
this.$emit('change', this.str2);
},
},
};
</script>
- 在父组件中,通过监听子组件的自定义事件来接收数据。例如:
<template>
<div>
<list @change="receiveDataFromChild"></list>
{{ str2 }}
</div>
</template>
<script>
import list from './list.vue';
export default {
components: { list },
data() {
return {
str2: '',
};
},
methods: {
receiveDataFromChild(value) {
this.str2 = value;
},
},
};
</script>
- 父组件直接获取子组件数据
- 父组件可以通过
this.$children
或this.$refs
来直接获取子组件的数据,但这种方式不常用,因为通过下标获取子组件可能会因为子组件的顺序变化而导致问题,而且代码的可读性和可维护性较差。例如:
- 父组件可以通过
<template>
<div>
<list ref="child"></list>
<button @click="getChildData">获取子组件数据</button>
{{ str2 }}
</div>
</template>
<script>
import list from './list.vue';
export default {
components: { list },
data() {
return {
str2: '',
};
},
methods: {
getChildData() {
this.str2 = this.$refs.child.str2;
},
},
};
</script>
(三)平辈之间传值
- 通常使用
bus
(事件总线)的方式进行平辈组件之间的传值。创建一个工具类bus.js
,用于实现全局的事件监听和触发。例如:
import Vue from 'vue';
export default new Vue();
- 在发送数据的组件中,通过触发
bus
的事件将数据传递出去。例如:
<template>
<div>
<button @click="sendDataToBrother">点击传值给兄弟组件</button>
</div>
</template>
<script>
import bus from './bus.js';
export default {
data() {
return {
str3: 'list 给兄弟的数据',
};
},
methods: {
sendDataToBrother() {
bus.$emit('change', this.str3);
},
},
};
</script>
- 在接收数据的组件中,通过监听
bus
的事件来接收数据。例如:
<template>
<div>{{ str3 }}</div>
</template>
<script>
import bus from './bus.js';
export default {
data() {
return {
str3: '',
};
},
mounted() {
bus.$on('change', (value) => {
this.str3 = value;
});
},
};
</script>
二、Vue3 中的组件传值方式
在 Vue3 中,组件传值的方式与 Vue2 有一些相似之处,但也有一些新的特性和变化。
(一)父传子
props
传值- 与 Vue2 类似,在父组件中通过属性绑定将数据传递给子组件,子组件通过
props
接收数据。例如:
- 与 Vue2 类似,在父组件中通过属性绑定将数据传递给子组件,子组件通过
<template>
<div>
<child :data="parentData"></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
components: { child },
data() {
return {
parentData: '父组件的数据',
};
},
};
</script>
<template>
<div>{{ data }}</div>
</template>
<script>
export default {
props: {
data: {
type: String,
default: '',
},
},
};
</script>
provide
和inject
- 在 Vue3 中,可以使用
provide
和inject
来实现跨层级的组件传值。例如:
- 在 Vue3 中,可以使用
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
components: { child },
provide() {
return {
parentData: '父组件提供的数据',
};
},
};
</script>
<template>
<div>{{ injectedData }}</div>
</template>
<script>
export default {
inject: ['parentData'],
data() {
return {
injectedData: '',
};
},
mounted() {
this.injectedData = this.parentData;
},
};
</script>
(二)子传父
- 自定义事件传值
- 和 Vue2 类似,在子组件中通过触发自定义事件将数据传递给父组件。例如:
<template>
<div>
<button @click="sendDataToParent">点击传值给父组件</button>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
methods: {
sendDataToParent() {
this.$emit('change', '子组件的数据');
},
},
});
</script>
<template>
<div>
<child @change="receiveDataFromChild"></child>
{{ parentData }}
</div>
</template>
<script>
import child from './child.vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: { child },
data() {
return {
parentData: '',
};
},
methods: {
receiveDataFromChild(value) {
this.parentData = value;
},
},
});
</script>
- 使用
ref
获取子组件实例- 在 Vue3 中,可以使用
ref
来获取子组件的实例,从而直接访问子组件的数据和方法。例如:
- 在 Vue3 中,可以使用
<template>
<div>
<child ref="childRef"></child>
<button @click="getChildData">获取子组件数据</button>
{{ parentData }}
</div>
</template>
<script>
import child from './child.vue';
import { defineComponent, ref } from 'vue';
export default defineComponent({
components: { child },
data() {
return {
parentData: '',
};
},
setup() {
const childRef = ref(null);
const getChildData = () => {
if (childRef.value) {
this.parentData = childRef.value.childData;
}
};
return {
childRef,
getChildData,
};
},
});
</script>
<template>
<div>{{ childData }}</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
data() {
return {
childData: '子组件的数据',
};
},
});
</script>
(三)平辈之间传值
- 在 Vue3 中,平辈之间的传值仍然可以使用事件总线或者状态管理工具(如
Pinia
、Vuex
)。
使用事件总线的方式与 Vue2 类似,创建一个全局的事件总线对象,在需要传值的组件中触发事件,在接收数据的组件中监听事件。
例如:
// bus.js
import { createApp } from 'vue';
export const bus = createApp({});
<template>
<div>
<button @click="sendDataToBrother">点击传值给兄弟组件</button>
</div>
</template>
<script>
import { bus } from './bus.js';
export default {
methods: {
sendDataToBrother() {
bus.$emit('change', '数据 from 组件 A');
},
},
};
</script>
<template>
<div>{{ receivedData }}</div>
</template>
<script>
import { bus } from './bus.js';
export default {
data() {
return {
receivedData: '',
};
},
mounted() {
bus.$on('change', (value) => {
this.receivedData = value;
});
},
};
</script>
三、总结
组件传值在 Vue 应用开发中是非常重要的环节。无论是 Vue2 还是 Vue3,都有多种方式实现组件之间的数据传递。在实际开发中,应根据具体的业务需求和项目结构选择合适的传值方式,以保证代码的可维护性和可读性。同时,随着 Vue 的不断发展,新的特性和工具也为组件传值提供了更多的选择和优化的可能。