vue2和vue3组件之间的通信方式差异

Vue2 vs Vue3 组件通信方法对比

1. 父子组件通信

1.1 Props 传递

Vue2

vue 复制代码
<!-- 父组件 -->
<template>
  <child-component :message="message"></child-component>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello'
    }
  }
}
</script>

<!-- 子组件 -->
<script>
export default {
  props: {
    message: String
  }
}
</script>

Vue3

vue 复制代码
<!-- 父组件 -->
<template>
  <child-component :message="message"></child-component>
</template>

<script setup>
import { ref } from 'vue'
const message = ref('Hello')
</script>

<!-- 子组件 -->
<script setup>
defineProps({
  message: String
})
</script>

1.2 自定义事件

Vue2

vue 复制代码
<!-- 子组件 -->
<template>
  <button @click="handleClick">点击</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$emit('custom-event', { data: 'value' })
    }
  }
}
</script>

<!-- 父组件 -->
<template>
  <child @custom-event="handleEvent"></child>
</template>

<script>
export default {
  methods: {
    handleEvent(data) {
      console.log(data)
    }
  }
}
</script>

Vue3

vue 复制代码
<!-- 子组件 -->
<template>
  <button @click="handleClick">点击</button>
</template>

<script setup>
const emit = defineEmits(['custom-event'])

const handleClick = () => {
  emit('custom-event', { data: 'value' })
}
</script>

<!-- 父组件 -->
<template>
  <child @custom-event="handleEvent"></child>
</template>

<script setup>
const handleEvent = (data) => {
  console.log(data)
}
</script>

2. 跨层级组件通信

2.1 provide/inject

Vue2

vue 复制代码
<!-- 祖先组件 -->
<script>
export default {
  provide() {
    return {
      theme: this.theme,
      updateTheme: this.updateTheme
    }
  },
  data() {
    return {
      theme: 'dark'
    }
  },
  methods: {
    updateTheme(value) {
      this.theme = value
    }
  }
}
</script>

<!-- 后代组件 -->
<script>
export default {
  inject: ['theme', 'updateTheme']
}
</script>

Vue3

vue 复制代码
<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue'

const theme = ref('dark')
const updateTheme = (value) => {
  theme.value = value
}

provide('theme', {
  theme,
  updateTheme
})
</script>

<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'

const { theme, updateTheme } = inject('theme')
</script>

2.2 事件总线

Vue2

javascript 复制代码
// eventBus.js
import Vue from 'vue'
export const eventBus = new Vue()

// 组件 A
this.eventBus.$emit('custom-event', data)

// 组件 B
mounted() {
  this.eventBus.$on('custom-event', this.handleEvent)
},
beforeDestroy() {
  this.eventBus.$off('custom-event', this.handleEvent)
}

Vue3

typescript 复制代码
// eventBus.ts
import mitt from 'mitt'
export const emitter = mitt()

// 组件 A
import { emitter } from './eventBus'
emitter.emit('custom-event', data)

// 组件 B
import { onMounted, onUnmounted } from 'vue'
import { emitter } from './eventBus'

onMounted(() => {
  emitter.on('custom-event', handleEvent)
})

onUnmounted(() => {
  emitter.off('custom-event', handleEvent)
})

3. 访问组件实例

3.1 ref 引用

Vue2

vue 复制代码
<!-- 父组件 -->
<template>
  <child-component ref="childRef"></child-component>
</template>

<script>
export default {
  mounted() {
    console.log(this.$refs.childRef.someData)
    this.$refs.childRef.someMethod()
  }
}
</script>

<!-- 子组件 -->
<script>
export default {
  data() {
    return {
      someData: 'value'
    }
  },
  methods: {
    someMethod() {
      // ...
    }
  }
}
</script>

Vue3

vue 复制代码
<!-- 父组件 -->
<template>
  <child-component ref="childRef"></child-component>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const childRef = ref(null)

onMounted(() => {
  console.log(childRef.value.someData)
  childRef.value.someMethod()
})
</script>

<!-- 子组件 -->
<script setup>
import { ref } from 'vue'

const someData = ref('value')
const someMethod = () => {
  // ...
}

defineExpose({
  someData,
  someMethod
})
</script>

3.2 父组件访问

Vue2

vue 复制代码
<!-- 子组件 -->
<script>
export default {
  methods: {
    accessParent() {
      console.log(this.$parent.parentData)
      this.$parent.parentMethod()
    }
  }
}
</script>

Vue3

vue 复制代码
<!-- 子组件 -->
<script setup>
import { getCurrentInstance } from 'vue'

const { proxy } = getCurrentInstance()
const accessParent = () => {
  console.log(proxy.$parent.parentData)
  proxy.$parent.parentMethod()
}
</script>

4. 主要差异总结

  1. 语法差异

    • Vue2 使用选项式 API
    • Vue3 推荐使用组合式 API 和 <script setup>
  2. 事件总线

    • Vue2 可以使用 Vue 实例作为事件总线
    • Vue3 移除了 on, off 等方法,需要使用第三方库(如 mitt)
  3. 组件实例访问

    • Vue2 可以直接访问组件实例的所有属性和方法
    • Vue3 需要通过 defineExpose 显式暴露要访问的属性和方法
  4. 响应式系统

    • Vue2 使用 Object.defineProperty
    • Vue3 使用 Proxy,提供了更好的响应式支持
  5. 性能优化

    • Vue3 提供了更好的性能优化机制
    • 组件通信的性能开销更小

5. 最佳实践建议

  1. 迁移策略

    • 逐步从 Vue2 迁移到 Vue3
    • 优先使用 Vue3 的新特性
    • 保持代码的一致性
  2. 代码组织

    • Vue3 中更推荐使用组合式 API
    • 将相关的逻辑组织在一起
    • 使用 hooks 复用逻辑
  3. 性能优化

    • 合理使用响应式数据
    • 避免不必要的组件通信
    • 及时清理事件监听器
相关推荐
一点一木3 小时前
深度体验TRAE SOLO移动端7天:作为独立开发者,我把工作流揣进了兜里
前端·人工智能·trae
天外飞雨道沧桑4 小时前
TypeScript 中 omit 和 record 用法
前端·javascript·typescript
Lee川4 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
canonical_entropy5 小时前
从 Spec-Driven Development 到 Attractor-Guided Engineering
前端·aigc·ai编程
研☆香5 小时前
聊聊前端页面的三种长度单位
前端
给钱,谢谢!5 小时前
React + PixiJS 实现果园成长页:从状态机到浇水动画
前端·react.js·前端框架
暗冰ཏོ6 小时前
VUE面试题大全
前端·javascript·vue.js·面试
次元工程师!6 小时前
LangFlow开发(三)—Bundles组件架构设计(3W+字详细讲解)
java·前端·python·低代码·langflow
Bug-制造者7 小时前
现代Web应用全栈开发:从架构设计到部署落地实战
前端
青春喂了后端8 小时前
IntelliGit 前端状态层重构:把一个全局 Store 拆成清晰的状态边界
前端·重构·状态模式