找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

601

积分

0

好友

77

主题
发表于 昨天 05:33 | 查看: 4| 回复: 0

Vue2 开发中,组件间的数据传递是核心技能。根据组件间的层级关系,通信方式主要分为父子组件传值、兄弟组件传值及跨层级组件传值。本文将系统梳理这些传值方案,并结合实现原理进行深度解析。

父子组件传值

父子组件关系由模板的嵌套使用决定。例如,在模板中使用了 Child 组件,它们之间便构成了父子关系。

<template>
  <div id="app">
    <Child/>
  </div>
</template>

<script>
import Child from './components/Child.vue';
export default {
  name: 'App',
  components: {
    Child
  }
}
</script>

父子组件间的数据流是单向的,具体可分为父传子和子传父两种情况。

父组件向子组件传值

父组件向子组件传值使用 v-bind(或其语法糖 :)传递数据,子组件通过 props 选项接收。props 支持类型检查、默认值设置和必填项验证。

父组件:

<Child :message="sendMsg" :obj="sendObj" />

<script>
...
data() {
  return {
    sendMsg: "sendxxxx",
    sendObj: {
      name: "zhangsan",
      age: 18
    }
  }
}
...
</script>

子组件:

<div>{{ message }} {{ obj }}</div>
...
<script>
props: {
  message: {
    type: String,
    required: true
  },
  obj: {
    type: Object
  }
}
</script>

页面将显示接收到的值。这种传递是响应式的,当父组件数据变化时,子组件会同步更新。

sendxxxx { "name": "zhangsan", "age": 18 }

子组件向父组件传值

子组件通过 $emit 触发自定义事件,父组件使用 v-on(或其语法糖 @)监听事件来接收数据。事件可以传递任意类型的数据。

子组件:

data() {
  return {
    transmitObj: {
      msg: "夏天夏天悄悄过去留下小秘密"
    },
    transmitString: "压心底压心底不要告诉你"
  }
},
created() {
  this.$emit("transmitObj", this.transmitObj)
  this.$emit("transmitStr", this.transmitString)
}

父组件:

<Child
  @transmitObj="handleTransmitObj"
  @transmitStr="handleTransmitStr"
/>
...
<script>
methods: {
  handleTransmitObj(params) {
    console.log("Child组件传递对象:", params);
  },
  handleTransmitStr(params) {
    console.log("Child组件传递字符串", params);
  }
}
</script>

Vue2父子组件传值流程图

兄弟组件间传值

兄弟组件间通信主要有两种思路:通过共同的父组件中转,或使用事件总线(Event Bus)。第一种方式本质上是父子通信的组合,不再赘述。重点介绍事件总线模式。

事件总线 (Event Bus)

事件总线是一种基于发布/订阅模式的简易全局通信方案。在 Vue2 中,可以利用 Vue 实例内置的 $on(订阅)、$emit(发布)和 $off(取消订阅)方法来实现。

首先,在项目入口文件(如 main.js)中创建并全局挂载一个事件总线实例:

// main.js
export const bus = new Vue()
Vue.prototype.$bus = bus;

你可能会好奇,为什么事件总线是一个 Vue 实例?这是因为每个 Vue 实例都自带了事件系统相关的 $on$emit$off 方法,其底层原理我们稍后探讨。先看用法,假设有两个兄弟组件:

Child组件(发布事件):

mounted(){
  this.$bus.$emit("msg", “夏天夏天”);
}

Brother组件(订阅事件):

created(){
  this.$bus.$on('msg', res => {
    console.log(“接收消息”, res)
  })
},
beforeDestroy(){
  // 组件销毁前移除监听,避免内存泄漏
  this.$bus.$off('msg')
}

通过以上代码,兄弟组件间就能完成通信。深入了解其背后的 JavaScript 事件机制,我们来看 Vue 源码是如何实现这三个核心方法的。

每个 Vue 实例在初始化时都会创建一个内部事件仓库 _events

// src/core/instance/events.js
export function initEvents (vm: Component) {
  vm._events = Object.create(null) // 空对象,用于存储事件
  vm._hasHookEvent = false
}
  1. $on 方法 (订阅) 当调用 $on('msg', fn) 时,回调函数 fn 会被存储到 _events 对象中,与事件名建立映射。

    Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
      const vm: Component = this
      if (Array.isArray(event)) { // 处理传入事件名数组的情况
        event.forEach(e => vm.$on(e, fn))
      } else {
        ;(vm._events[event] || (vm._events[event] = [])).push(fn)
      }
      return vm
    }
  2. $emit 方法 (发布) 当调用 $emit('msg', data) 时,会从 _events 中取出对应事件名的回调函数队列并依次执行。

    Vue.prototype.$emit = function (event: string): Component {
      const vm: Component = this
      let cbs = vm._events[event]
      if (cbs) {
        const args = toArray(arguments, 1) // 获取$emit除事件名外的参数
        for (let i = 0; i < cbs.length; i++) {
          try {
            cbs[i].apply(vm, args) // 执行回调
          } catch (e) {
            handleError(e, vm, `event handler for "${event}"`)
          }
        }
      }
      return vm
    }
  3. $off 方法 (取消订阅) 用于移除事件监听器,是防止内存泄漏的关键。

    Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component {
      const vm: Component = this;
      // 如果不传参数,移除所有事件监听
      if (!arguments.length) {
        vm._events = Object.create(null);
        return vm;
      }
      // 如果event是数组,遍历处理
      if (Array.isArray(event)) {
        event.forEach(e => vm.$off(e, fn));
        return vm;
      }
      const cbs = vm._events[event];
      if (!cbs) {
        return vm;
      }
      // 如果只传了事件名,移除该事件所有监听
      if (arguments.length === 1) {
        vm._events[event] = null;
        return vm;
      }
      // 如果指定了具体回调函数,则只移除该函数
      if (fn) {
        vm._events[event] = cbs.filter(cb => cb !== fn && cb.fn !== fn);
      }
      return vm;
    };

provide / inject

provideinject 是 Vue 提供的依赖注入 API,主要用于祖先组件向任意深度的后代组件传递数据或方法,无需通过 props 逐层传递。在 Vue2 中,默认情况下注入的值不是响应式的,若需响应性需要传递一个响应式对象(如父组件 data 中的对象)。

其典型使用场景是全局配置,如主题、语言、用户信息等。对于需要集中管理、频繁变化的复杂应用状态,更推荐使用专业的 前端框架 状态管理库,如 Vuex 或 Pinia。




上一篇:Ceph集群扩容实战避坑:Quincy版本下渐进式权重调整方案
下一篇:大模型框架深度评测:Megatron、vLLM与RLHF框架的选型与实践指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-11 03:24 , Processed in 0.078824 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表