在 uni-app 中,组件间的传参是开发中常见的需求。以下是不同场景下的传参方法及其详细示例,结合 uni-app 的特性和 Vue 的语法。
1. 父组件向子组件传参(props
)
适用场景:父组件向子组件传递数据(如配置项、初始值)。
步骤:
父组件绑定属性:
<template> <ChildComponent :message="parentMessage" /> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { parentMessage: 'Hello from parent!' }; } }; </script>
子组件接收
props
:<script> export default { props: { message: { type: String, required: true } }, mounted() { console.log(this.message); // 输出:Hello from parent! } }; </script>
2. 子组件向父组件传参($emit
)
适用场景:子组件向父组件传递数据(如按钮点击事件、表单提交)。
步骤:
子组件触发事件:
<template> <button @click="sendData">发送数据</button> </template> <script> export default { methods: { sendData() { const data = 'Hello from child!'; this.$emit('child-event', data); } } }; </script>
父组件监听事件:
<template> <ChildComponent @child-event="handleData" /> <p>{{ receivedData }}</p> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent }, data() { return { receivedData: '' }; }, methods: { handleData(data) { this.receivedData = data; // 输出:Hello from child! } } }; </script>
3. 跨级组件传参($attrs
和 $listeners
)
适用场景:祖孙组件或深层嵌套组件传参。
步骤:
父组件传递属性:
<template> <GrandChildComponent v-bind="parentData" /> </template> <script> import GrandChildComponent from './GrandChildComponent.vue'; export default { components: { GrandChildComponent }, data() { return { parentData: { name: 'Tom', age: 30 } }; } }; </script>
中间组件透传属性:
<template> <GrandChildComponent v-bind="$attrs" v-on="$listeners" /> </template> <script> import GrandChildComponent from './GrandChildComponent.vue'; export default { components: { GrandChildComponent } }; </script>
孙组件接收属性:
<script> export default { props: ['name', 'age'] }; </script>
4. 全局状态管理(Vuex / Pinia)
适用场景:跨多个组件共享状态(如用户登录状态、购物车)。
Pinia 示例:
创建 Store:
// stores/userStore.js import { defineStore } from 'pinia'; export const useUserStore = defineStore('user', { state: () => ({ username: 'Guest' }) });
组件中使用 Store:
<template> <p>当前用户:{{ username }}</p> </template> <script> import { useUserStore } from '@/stores/userStore'; export default { setup() { const userStore = useUserStore(); return { username: userStore.username }; } }; </script>
5. 使用 event-bus
实现跨组件通信
适用场景:非父子组件间通信(如页面间传参、全局事件)。
步骤:
创建事件总线:
// event-bus.js import Vue from 'vue'; export const EventBus = new Vue();
组件 A 发送事件:
<script> import { EventBus } from './event-bus.js'; export default { methods: { sendData() { EventBus.$emit('message-event', 'Hello from Component A'); } } }; </script>
组件 B 监听事件:
<script> import { EventBus } from './event-bus.js'; export default { created() { EventBus.$on('message-event', (msg) => { console.log(msg); // 输出:Hello from Component A }); }, beforeDestroy() { EventBus.$off('message-event'); // 避免内存泄漏 } }; </script>
6. 页面间传参(URL 参数)
适用场景:页面跳转时传递简单参数(如 ID、名称)。
示例:
A 页面跳转并传递参数:
uni.navigateTo({ url: '/pages/B/B?param1=value1¶m2=value2' });
B 页面接收参数:
onLoad(options) { console.log(options.param1); // 输出:value1 console.log(options.param2); // 输出:value2 }
7. 页面间传参(本地存储 storage
)
适用场景:传递复杂数据或大体积数据。
示例:
A 页面存储数据:
uni.setStorageSync('key', { name: 'Tom', age: 30 }); uni.navigateTo({ url: '/pages/B/B' });
B 页面读取数据:
onLoad() { const data = uni.getStorageSync('key'); console.log(data.name); // 输出:Tom console.log(data.age); // 输出:30 }
8. 使用 getCurrentPages
传递数据
适用场景:返回上一个页面时传递数据(如表单提交后刷新数据)。
示例:
B 页面修改数据并返回:
const pages = getCurrentPages(); const prevPage = pages[pages.length - 2]; // 获取上一个页面 prevPage.setData({ refreshData: true }); uni.navigateBack();
A 页面监听数据变化:
onShow() { if (this.data.refreshData) { this.fetchData(); // 刷新数据 } }
9. 使用 ref
直接访问子组件
适用场景:父组件直接调用子组件的方法或修改属性。
示例:
父组件调用子组件方法:
<template> <ChildComponent ref="childRef" /> <button @click="callChildMethod">调用子组件方法</button> </template> <script> export default { methods: { callChildMethod() { this.$refs.childRef.customMethod(); } } }; </script>
子组件定义方法:
<script> export default { methods: { customMethod() { console.log('子组件方法被调用'); } } }; </script>
10. 使用 provide
/ inject
传递数据
适用场景:祖先组件向子孙组件传递数据(如主题色、全局配置)。
示例:
祖先组件提供数据:
<script> export default { provide() { return { theme: 'dark' }; } }; </script>
子孙组件注入数据:
<script> export default { inject: ['theme'], mounted() { console.log(this.theme); // 输出:dark } }; </script>
总结
方法 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
props / $emit |
父子组件通信 | 简单直观 | 不支持跨级通信 |
$attrs / $listeners |
多层组件通信 | 避免逐层传递 | 需手动处理 |
provide / inject |
跨层级传参 | 简化嵌套组件通信 | 不支持响应式更新 |
v-model |
双向绑定 | 简化表单逻辑 | 仅适用于特定场景 |
事件总线 | 兄弟组件通信 | 灵活 | 可能导致内存泄漏 |
ref |
父组件直接操作子组件 | 直接控制 | 破坏封装性 |
状态管理工具 | 全局状态共享 | 高效管理复杂状态 | 需额外配置 |
根据具体需求选择合适的方法,保持组件间通信的简洁性和可维护性。