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. 性能优化

    • 合理使用响应式数据
    • 避免不必要的组件通信
    • 及时清理事件监听器
相关推荐
祈澈菇凉2 分钟前
==和===在不同场景下的具体区别是什么?
前端
_xaboy5 分钟前
FcDesigner页面样式错乱/功能不正常解决办法
vue.js·低代码·开源·动态表单·表单设计器
陆沙16 分钟前
D3.js-简单入门2-动态图表&交互操作
开发语言·javascript·交互
雪花凌落的盛夏30 分钟前
go语言因为前端跨域导致无法访问到后端解决方案
开发语言·前端·golang
青红光硫化黑40 分钟前
前端基础之ajax
前端·javascript·ajax
阿金要当大魔王~~1 小时前
table上下移动
javascript·css·css3
再吃一根胡萝卜1 小时前
antd实现一个带有输入框的确认删除对话框
前端
yinxiangzhongqing1 小时前
es6常见知识点
javascript·es6·原型模式
yinxiangzhongqing1 小时前
深入理解JavaScript的执行机制
开发语言·前端·javascript
问道飞鱼1 小时前
【前端知识】基于Lit的复杂组件开发
前端·web components·lit