1. 逐层传递(props 和 $emit)
props 从父组件传递到子组件,子组件可通过 $emit 触发自定义事件将数据传递给父组件
props
<!-- 父组件 -->
<template>
<Child :msg="data" />
</template>
<script>
import Child from './Child.vue';
export default {
components: { Child },
data() {
return { data: '顶层数据' }
}
}
</script>
<!-- 子组件 -->
<template>
<GrandChild :message="msg" />
</template>
<script>
import GrandChild from './GrandChild.vue';
export default {
components: { GrandChild },
props: ['msg']
}
</script>
<!-- 孙组件 -->
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
props: ['message']
}
</script>
$emit
<!-- 父组件 -->
<template>
<Child @update="data = $event" />
<p>{{ data }}</p>
</template>
<script>
import Child from './Child.vue';
export default {
components: { Child },
data() {
return { data: '初始值' }
}
}
</script>
<!-- 子组件 -->
<template>
<GrandChild @change="handleChange" />
</template>
<script>
import GrandChild from './GrandChild.vue';
export default {
components: { GrandChild },
methods: {
handleChange(value) {
this.$emit('update', value);
}
}
}
</script>
<!-- 孙组件 -->
<template>
<button @click="sendData">点击</button>
</template>
<script>
export default {
methods: {
sendData() {
this.$emit('change', '来自底层的数据');
}
}
}
</script>
2. 事件总线(Event Bus)
事件总线是一个全局的事件发射器,可用于在不同组件间传递数据,无需考虑组件的嵌套关系
<!-- 顶层组件:App.vue -->
<template>
<div>
<DeepChildComponent />
<p>接收到的数据: {{ receivedData }}</p>
</div>
</template>
<script>
import { eventBus } from './EventBus.js';
import DeepChildComponent from './DeepChildComponent.vue';
export default {
components: { DeepChildComponent },
data() {
return {
receivedData: ''
};
},
created() {
eventBus.$on('data-updated', (data) => {
this.receivedData = data;
});
},
beforeDestroy() {
eventBus.$off('data-updated');
}
};
</script>
<!-- 深层子组件:DeepChildComponent.vue -->
<template>
<button @click="sendData">发送数据</button>
</template>
<script>
import { eventBus } from './EventBus.js';
export default {
methods: {
sendData() {
eventBus.$emit('data-updated', '深层数据');
}
}
};
</script>
3. Vuex 状态管理
// store.js
import { createStore } from 'vuex';
export default createStore({
state: {
message: '初始消息'
},
mutations: {
SET_MESSAGE(state, payload) {
state.message = payload;
}
},
actions: {
updateMessage({ commit }, payload) {
commit('SET_MESSAGE', payload);
}
},
getters: {
getMessage: (state) => state.message
}
});
//App.vue
<template>
<div>
<h1>父组件</h1>
<p>消息: {{ message }}</p>
<ChildComponent />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
import { mapGetters } from 'vuex';
export default {
components: { ChildComponent },
computed: {
...mapGetters(['getMessage']),
message() {
return this.getMessage;
}
}
};
</script>
//ChildComponent.vue
<template>
<div>
<h2>深层子组件</h2>
<button @click="updateMessage('来自深层组件的消息')">
更新消息
</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions(['updateMessage'])
}
};
</script>
- 定义状态:在 store 中定义
message - 读取状态:父组件通过
mapGetters获取message - 修改状态:子组件通过
mapActions触发updateMessage - 自动更新:所有使用
message的组件会自动更新
4. provide 和 inject
provide 和 inject 是 Vue 提供的一对用于实现跨级组件数据传递的选项provide 选项允许一个组件向其所有子孙组件注入一个依赖,不论组件嵌套有多深,都能在其子孙组件中通过 inject 选项来使用这个依赖。不过这种方式是单向的,由父组件流向子组件,且一旦注入就不能在子组件中修改父组件提供的数据。
//父组件(提供数据)
<template>
<ChildComponent />
</template>
<script>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
setup() {
const message = ref('顶层数据');
// 提供数据
provide('message', message);
return {};
}
};
</script>
//深层子组件(注入数据)
<template>
<p>{{ message.value }}</p>
</template>
<script>
import { inject } from 'vue';
export default {
setup() {
// 注入数据
const message = inject('message');
return { message };
}
};
</script>
- provide:父组件通过
provide('key', value)提供数据 - inject:任意后代组件通过
inject('key')获取数据 - 响应式:使用
ref包裹的数据会自动响应更新