返回

Vue 组件间通信的奇妙世界:六种方式深入实践指南

前端

在 Vue.js 中,组件是构建用户界面的基本单位。组件之间的数据和事件是如何通信的呢?本文将介绍 Vue 组件间通信的六种方式,包括父子组件通信、兄弟组件通信、隔代组件通信、事件总线、状态管理和 provide/inject。

1. 父子组件通信

父子组件通信是最常见的一种组件通信方式。父组件可以向子组件传递数据,也可以监听子组件发出的事件。

传递数据

父组件可以通过 props 向子组件传递数据。props 是只读的,子组件不能修改 props 的值。

<!-- 父组件 -->
<template>
  <child-component :message="message" />
</template>

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

<!-- 子组件 -->
<template>
  <p>{{ message }}</p>
</template>

<script>
export default {
  props: ['message']
}
</script>

监听事件

子组件可以通过 $emit 方法向父组件发出事件。父组件可以通过 v-on 指令监听子组件发出的事件。

<!-- 父组件 -->
<template>
  <child-component @message="handleMessage" />
</template>

<script>
export default {
  methods: {
    handleMessage(message) {
      console.log(message)
    }
  }
}
</script>

<!-- 子组件 -->
<template>
  <button @click="handleClick">点击我</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$emit('message', 'Hello, Vue!')
    }
  }
}
</script>

2. 兄弟组件通信

兄弟组件通信是指两个没有直接父子关系的组件之间的通信。

事件总线

事件总线是一种组件间通信的方式,它允许组件通过一个中央事件总线发布和订阅事件。

<!-- 主组件 -->
<template>
  <component-a @message="handleMessage" />
  <component-b @message="handleMessage" />
</template>

<script>
export default {
  data() {
    return {
      message: ''
    }
  },
  methods: {
    handleMessage(message) {
      this.message = message
    }
  }
}
</script>

<!-- 组件 A -->
<template>
  <button @click="handleClick">点击我</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$emit('message', 'Hello, Vue!')
    }
  }
}
</script>

<!-- 组件 B -->
<template>
  <p>{{ message }}</p>
</template>

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

状态管理

状态管理是一种组件间通信的方式,它允许组件共享一个全局的状态。

<!-- 主组件 -->
<template>
  <component-a />
  <component-b />
</template>

<script>
import { createStore } from 'vuex'

export default {
  data() {
    return {
      store: createStore({
        state: {
          message: ''
        },
        mutations: {
          setMessage(state, message) {
            state.message = message
          }
        }
      })
    }
  }
}
</script>

<!-- 组件 A -->
<template>
  <button @click="handleClick">点击我</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$store.commit('setMessage', 'Hello, Vue!')
    }
  }
}
</script>

<!-- 组件 B -->
<template>
  <p>{{ $store.state.message }}</p>
</template>

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

3. 隔代组件通信

隔代组件通信是指祖先组件和孙子组件之间的通信。

provide/inject

provide/inject 是一种组件间通信的方式,它允许祖先组件向其所有子孙组件提供数据。

<!-- 祖先组件 -->
<template>
  <child-component />
</template>

<script>
export default {
  provide() {
    return {
      message: 'Hello, Vue!'
    }
  }
}
</script>

<!-- 子组件 -->
<template>
  <grandchild-component />
</template>

<script>
export default {
  inject: ['message']
}
</script>

<!-- 孙子组件 -->
<template>
  <p>{{ message }}</p>
</template>

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

4. props + events

props + events 是另一种常见的组件间通信方式,它结合了 props 和事件总线。

props

props 是只读的,子组件不能修改 props 的值。

<!-- 父组件 -->
<template>
  <child-component :message="message" @message="handleMessage" />
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  methods: {
    handleMessage(message) {
      console.log(message)
    }
  }
}
</script>

<!-- 子组件 -->
<template>
  <p>{{ message }}</p>
  <button @click="handleClick">点击我</button>
</template>

<script>
export default {
  props: ['message'],
  methods: {
    handleClick() {
      this.$emit('message', 'Hello, Vue!')
    }
  }
}
</script>

5. parent/refs

parent 和 refs 是 Vue 中内置的两个属性,它们可以用来访问父组件和子组件。

$parent

$parent 属性可以用来访问父组件。

<!-- 子组件 -->
<template>
  <p>{{ $parent.message }}</p>
</template>

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

$refs

$refs 属性可以用来访问子组件。

<!-- 父组件 -->
<template>
  <child-component ref="child" />
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  methods: {
    handleMessage() {
      console.log(this.$refs.child.message)
    }
  }
}
</script>

<!-- 子组件 -->
<template>
  <p>{{ message }}</p>
</template>

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

6. 插槽

插槽是一种组件间通信的方式,它允许父组件向子组件提供内容。

<!-- 父组件 -->
<template>
  <child-component>
    <p>Hello, Vue!</p>
  </child-component>
</template>

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

<!-- 子组件 -->
<template>
  <div>
    <slot />
  </div>
</template>

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

总结

Vue 组件间通信的六种方式各有优缺点,具体使用哪种方式取决于项目的具体需求。