一、Props
Props 是父组件向子组件传递数据的常用方式。
在父组件模板里,通过在子组件标签上绑定属性来传递数据:
<template>
<ChildComponent :message="parentMessage" />
</template>
子组件则通过 defineProps
接收:
import { defineComponent, defineProps } from 'vue';
export default defineComponent({
props: defineProps({
message: String
}),
setup(props) {
// 打印接收到的消息
console.log(props.message);
return {};
}
});
通过上述代码,父组件可以将 parentMessage
的值传递给子组件,子组件通过 defineProps
接收并使用。
二、Emits
Emits 用于子组件向父组件传递事件。
子组件用 defineEmits
定义可触发的事件,通过 emit
函数触发,父组件用 @
(v-on 语法糖)监听。
子组件代码如下:
import { defineComponent, defineEmits } from 'vue';
export default defineComponent({
emits: defineEmits(['childEvent']),
setup(props, { emit }) {
const handleClick = () => {
// 触发 childEvent 事件并传递数据
emit('childEvent', 'Data from child');
};
return {
handleClick
};
}
});
父组件监听代码如下:
<template>
<ChildComponent @childEvent="handleChildEvent" />
</template>
三、Provide/Inject
Provide/Inject 用于跨多层组件的数据传递。
祖先组件用 provide
提供数据,后代组件用 inject
获取。如果提供的是响应式数据(如 ref
或 reactive
),后代获取的数据也是响应式的。
祖先组件:
import { defineComponent, provide } from 'vue';
import GrandchildComponent from './GrandchildComponent.vue';
export default defineComponent({
setup() {
const sharedData = 'This is shared data';
// 提供 sharedData 数据
provide('sharedData', sharedData);
return {
sharedData
};
},
components: {
GrandchildComponent
}
});
后代组件:
import { defineComponent, inject } from 'vue';
export default defineComponent({
setup() {
// 获取 sharedData 数据
const sharedData = inject('sharedData');
console.log(sharedData);
return {};
}
});
四、Vuex(状态管理库)
Vuex 用于管理应用全局状态。
先创建 store
存储状态、定义 mutations
修改状态等。组件通过 useStore
访问状态,也可以用 mapState
、mapMutations
等辅助函数。
定义 store
(store/index.js):
import { createStore } from 'vuex';
const store = createStore({
state() {
return {
count: 0
};
},
mutations: {
increment(state) {
// 状态中的 count 加 1
state.count++;
}
});
export default store;
组件使用:
import { defineComponent } from 'vue';
import { useStore } from 'vuex';
export default defineComponent({
setup() {
const store = useStore();
const count = computed(() => store.state.count);
const increment = () => {
// 调用 increment 方法修改状态
store.commit('increment');
};
return {
count,
increment
};
}
});
五、Event Bus(自定义事件总线)
可以借助第三方库(如 mitt
)创建事件总线来通信。一个组件发送事件,另一个接收,但可能会使代码维护性变差。
创建事件总线(event-bus.js):
import mitt from'mitt';
const emitter = mitt();
export default emitter;
组件 A 发送:
import emitter from './event-bus.js';
export default {
setup() {
const sendEvent = () => {
// 发送自定义事件
emitter.emit('customEvent', 'Data from component A');
};
return {
sendEvent
};
}
};
组件 B 接收:
import emitter from './event-bus.js';
export default {
setup() {
emitter.on('customEvent', (data) => {
// 接收自定义事件并打印数据
console.log(data);
});
return {};
}
};
六、Slots(插槽)
1. 默认插槽
默认插槽是父组件向子组件传递内容的基本方式。
父组件在子组件标签内放内容,子组件用 <slot>
标签渲染。
父组件:
<template>
<ChildComponent>
<p>Content passed to child via default slot</p>
</ChildComponent>
</template>
子组件:
<template>
<div>
<slot></slot>
</div>
</template>
2. 具名插槽
具名插槽用于传递不同部分内容。
父组件用 v-slot
(或 #
语法糖)指定插槽名和内容,子组件用 name
属性区分插槽。
父组件:
<template>
<ChildComponent>
<template v-slot:header>
<h1>Header content</h1>
</template>
<template v-slot:body>
<p>Body content</p>
</template>
</ChildComponent>
</template>
子组件:
<template>
<div>
<slot name="header"></slot>
<slot name="body"></slot>
</div>
</template>
3. 作用域插槽
作用域插槽允许子组件向父组件传递数据,父组件自定义数据渲染方式。
子组件:
<template>
<slot :data="childData"></slot>
</template>
父组件:
<template>
<ChildComponent>
<template v-slot="slotProps">
<p>{{slotProps.data}}</p>
</template>
</ChildComponent>
</template>
七、Composition API 共享状态
通过创建组合函数共享数据。
组合函数返回响应式数据和操作数据的函数,多个组件可使用同一组合函数共享状态。
组合函数(useCounter.js):
import { ref } from 'vue';
export const useCounter = () => {
const count = ref(0);
const increment = () => {
// 计数器加 1
count.value++;
};
return {
count,
increment
};
};
组件 A 使用:
import { defineComponent } from 'vue';
import { useCounter } from './useCounter.js';
export default defineComponent({
setup() {
const { count, increment } = useCounter();
return {
count,
increment
};
}
});
同理组件 B 也可使用该组合函数来共享状态。
通过上述这些 Vue.js 中的组件通信和状态管理方式,我们可以根据不同的需求,灵活地构建出功能强大、结构清晰的 Vue.js 应用。希望这篇博客对你有所帮助,在实际开发中可以根据具体情况选择合适的方式。