uni-app组件通信

发布于:2025-07-03 ⋅ 阅读:(24) ⋅ 点赞:(0)

uni-app 中,组件间的传参是开发中常见的需求。以下是不同场景下的传参方法及其详细示例,结合 uni-app 的特性和 Vue 的语法。


1. 父组件向子组件传参(props

适用场景:父组件向子组件传递数据(如配置项、初始值)。

步骤
  1. 父组件绑定属性

    <template>
      <ChildComponent :message="parentMessage" />
    </template>
    <script>
    import ChildComponent from './ChildComponent.vue';
    export default {
      components: { ChildComponent },
      data() {
        return {
          parentMessage: 'Hello from parent!'
        };
      }
    };
    </script>
  2. 子组件接收 props

    <script>
    export default {
      props: {
        message: {
          type: String,
          required: true
        }
      },
      mounted() {
        console.log(this.message); // 输出:Hello from parent!
      }
    };
    </script>

2. 子组件向父组件传参($emit

适用场景:子组件向父组件传递数据(如按钮点击事件、表单提交)。

步骤
  1. 子组件触发事件

    <template>
      <button @click="sendData">发送数据</button>
    </template>
    <script>
    export default {
      methods: {
        sendData() {
          const data = 'Hello from child!';
          this.$emit('child-event', data);
        }
      }
    };
    </script>
  2. 父组件监听事件

    <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

适用场景:祖孙组件或深层嵌套组件传参。

步骤
  1. 父组件传递属性

    <template>
      <GrandChildComponent v-bind="parentData" />
    </template>
    <script>
    import GrandChildComponent from './GrandChildComponent.vue';
    export default {
      components: { GrandChildComponent },
      data() {
        return {
          parentData: {
            name: 'Tom',
            age: 30
          }
        };
      }
    };
    </script>
  2. 中间组件透传属性

    <template>
      <GrandChildComponent v-bind="$attrs" v-on="$listeners" />
    </template>
    <script>
    import GrandChildComponent from './GrandChildComponent.vue';
    export default {
      components: { GrandChildComponent }
    };
    </script>
  3. 孙组件接收属性

    <script>
    export default {
      props: ['name', 'age']
    };
    </script>

4. 全局状态管理(Vuex / Pinia)

适用场景:跨多个组件共享状态(如用户登录状态、购物车)。

Pinia 示例
  1. 创建 Store

    // stores/userStore.js
    import { defineStore } from 'pinia';
    export const useUserStore = defineStore('user', {
      state: () => ({
        username: 'Guest'
      })
    });
  2. 组件中使用 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 实现跨组件通信

适用场景:非父子组件间通信(如页面间传参、全局事件)。

步骤
  1. 创建事件总线

    // event-bus.js
    import Vue from 'vue';
    export const EventBus = new Vue();
  2. 组件 A 发送事件

    <script>
    import { EventBus } from './event-bus.js';
    export default {
      methods: {
        sendData() {
          EventBus.$emit('message-event', 'Hello from Component A');
        }
      }
    };
    </script>
  3. 组件 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、名称)。

示例
  1. A 页面跳转并传递参数

    uni.navigateTo({
      url: '/pages/B/B?param1=value1¶m2=value2'
    });
  2. B 页面接收参数

    onLoad(options) {
      console.log(options.param1); // 输出:value1
      console.log(options.param2); // 输出:value2
    }

7. 页面间传参(本地存储 storage

适用场景:传递复杂数据或大体积数据。

示例
  1. A 页面存储数据

    uni.setStorageSync('key', { name: 'Tom', age: 30 });
    uni.navigateTo({ url: '/pages/B/B' });
  2. B 页面读取数据

    onLoad() {
      const data = uni.getStorageSync('key');
      console.log(data.name); // 输出:Tom
      console.log(data.age); // 输出:30
    }

8. 使用 getCurrentPages 传递数据

适用场景:返回上一个页面时传递数据(如表单提交后刷新数据)。

示例
  1. B 页面修改数据并返回

    const pages = getCurrentPages();
    const prevPage = pages[pages.length - 2]; // 获取上一个页面
    prevPage.setData({ refreshData: true });
    uni.navigateBack();
  2. A 页面监听数据变化

    onShow() {
      if (this.data.refreshData) {
        this.fetchData(); // 刷新数据
      }
    }

9. 使用 ref 直接访问子组件

适用场景:父组件直接调用子组件的方法或修改属性。

示例
  1. 父组件调用子组件方法

    <template>
      <ChildComponent ref="childRef" />
      <button @click="callChildMethod">调用子组件方法</button>
    </template>
    <script>
    export default {
      methods: {
        callChildMethod() {
          this.$refs.childRef.customMethod();
        }
      }
    };
    </script>
  2. 子组件定义方法

    <script>
    export default {
      methods: {
        customMethod() {
          console.log('子组件方法被调用');
        }
      }
    };
    </script>

10. 使用 provide / inject 传递数据

适用场景:祖先组件向子孙组件传递数据(如主题色、全局配置)。

示例
  1. 祖先组件提供数据

    <script>
    export default {
      provide() {
        return {
          theme: 'dark'
        };
      }
    };
    </script>
  2. 子孙组件注入数据

    <script>
    export default {
      inject: ['theme'],
      mounted() {
        console.log(this.theme); // 输出:dark
      }
    };
    </script>

总结

方法 适用场景 优点 缺点
props / $emit 父子组件通信 简单直观 不支持跨级通信
$attrs / $listeners 多层组件通信 避免逐层传递 需手动处理
provide / inject 跨层级传参 简化嵌套组件通信 不支持响应式更新
v-model 双向绑定 简化表单逻辑 仅适用于特定场景
事件总线 兄弟组件通信 灵活 可能导致内存泄漏
ref 父组件直接操作子组件 直接控制 破坏封装性
状态管理工具 全局状态共享 高效管理复杂状态 需额外配置

根据具体需求选择合适的方法,保持组件间通信的简洁性和可维护性。