你的复习资料之——vue组件通信

413 阅读2分钟

Vue.js 组件间通信指南

Vue.js 是一种灵活的前端框架,提供了多种组件间通信的方式。本文将详细介绍 Vue 中几种常用的通信方法,包括基本的 props 传递、自定义事件、事件总线、v-model 双向绑定、sync 属性修饰符、$attrs$listeners 的使用、$children$parent 的访问、provideinject 的高级应用,以及 Vuex 状态管理库的集成。

一、组件间通信最基本方式: props

props 是父组件传递给子组件的数据。在父组件中,通过在子组件标签上绑定属性并传递相应的值来传递数据;在子组件中,则需要在 props 选项中声明接收哪些属性,并在组件中使用这些属性。

注意点:

  • 确保在子组件中正确声明所有从父组件接收的 props
  • 如果 props 是对象或数组类型,应当考虑深拷贝以避免意外更改原始数据。

示例

父组件

<template>
  <child-component :message="message" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

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

子组件

<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: {
    message: String
  }
}
</script>

二、组件间通信2: Vue自定义事件

除了通过 props 进行父子组件之间的通信,Vue 还提供了一种更加灵活的组件间通信方式,即自定义事件。通过自定义事件,可以让子组件向父组件发送消息,也可以让任意两个组件之间进行通信。

注意点:

  • 当使用 $emit 触发事件时,确保父组件已经监听了这个事件。
  • 事件名称应当遵循约定的命名规范,例如使用 kebab-case。

示例

子组件

<template>
  <button @click="sendMessage">发送消息</button>
</template>

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

父组件

<template>
  <child-component @message="handleMessage" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

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

三、组件间通信3: 事件总线

事件总线是一个 Vue 实例,可以用来在任意两个组件之间进行通信。事件总线可以通过 Vue 的全局事件机制来实现,即使用 $emit 方法触发一个全局事件,然后在需要监听这个事件的组件中使用 $on 方法进行监听。

注意点:

  • 事件总线是一种全局的通信方式,应当谨慎使用,以免导致组件间的耦合过高。
  • 在组件销毁时取消事件监听,以避免内存泄漏。

示例

创建全局事件总线

// event-bus.js
import Vue from 'vue';

export const eventBus = new Vue();

组件 A(发送消息)

import { eventBus } from './event-bus.js';

export default {
  methods: {
    sendMessage() {
      eventBus.$emit('message', 'Hello World!');
    }
  }
}

组件 B(接收消息)

import { eventBus } from './event-bus.js';

export default {
  created() {
    eventBus.$on('message', message => {
      console.log(message);
    });
  },
  beforeDestroy() {
    eventBus.$off('message');
  }
}

四、组件间通信4: v-model

v-model 是 Vue 提供的一个用于双向绑定的指令,它可以方便地在父组件和子组件之间进行双向数据绑定。

注意点:

  • v-model 实际上是语法糖,它简化了 value prop 和 input 事件的绑定。
  • 当使用 v-model 时,确保子组件正确实现了 input 事件。

示例

自定义输入框组件

<template>
  <input :value="value" @input="$emit('input', $event.target.value)">
</template>

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

父组件

<template>
  <custom-input v-model="message" />
</template>

<script>
import CustomInput from './CustomInput.vue';

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

五、组件间通信5: sync 属性修饰符

sync 是 Vue 提供的一个属性修饰符,它可以方便地实现子组件向父组件传递数据并保持同步更新。

注意点:

  • sync 修饰符仅适用于 v-model 的情况。
  • 确保子组件正确实现了 update:value 事件。

示例

自定义输入框组件

<template>
  <input :value="value" @input="$emit('update:value', $event.target.value)">
</template>

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

父组件

<template>
  <custom-input :value.sync="message" />
</template>

<script>
import CustomInput from './CustomInput.vue';

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

六、组件间通信6: $attrs$listeners

在 Vue 组件开发中,有时候需要在组件之间传递一些未被声明为 prop 的数据或监听父组件的事件,这时候可以使用 Vue 提供的 $attrs$listeners 特殊属性来实现。

注意点:

  • $attrs 包含了父组件传递给子组件但在子组件中未被声明的属性。
  • $listeners 包含了父组件绑定在当前组件上的所有事件监听器。
  • 要禁用特性继承,请设置 inheritAttrsfalse

示例

组件

<template>
  <div>
    <input v-bind="$attrs" />
    <!-- 或者 -->
    <custom-component v-bind="$attrs" />
  </div>
</template>

<script>
export default {
  inheritAttrs: false // 禁用特性继承
}
</script>

组件

<template>
  <div v-on="$listeners">
    <input />
    <!-- 或者 -->
    <custom-component v-on="$listeners" />
  </div>
</template>

七、组件间通信7: $children$parent

在 Vue 组件开发中,$children$parent 是两个特殊的属性,可以用于实现组件之间的通信。

注意点:

  • $children 数组是不稳定的,其顺序可能受到组件渲染顺序的影响。
  • $parent 只能访问当前组件的直接父组件实例。
  • 不推荐使用 $children$parent 来访问子组件和父组件,因为这可能导致组件之间的耦合和不可预测的问题。

示例

父组件

<template>
  <div>
    <child-component ref="child"></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  mounted() {
    // 访问子组件实例的属性和方法
    console.log(this.$children[0].childProp)
    this.$children[0].childMethod()

    // 通过 ref 访问子组件实例
    console.log(this.$refs.child.childProp)
    this.$refs.child.childMethod()
  }
}
</script>

八、组件间通信8: provideinject

Vue 提供了一种比较高级的组件通信方式 —— provideinject,它可以实现祖先组件向后代组件传递数据,而无需一层层地传递 props 或者事件。

注意点:

  • provideinject 主要用于高阶组件库和插件开发。
  • 在业务组件中不推荐使用 provideinject,因为它会增加组件之间的耦合性。
  • 如果需要在业务组件中实现组件之间的通信,建议使用 Vuex 或事件总线等官方推荐的通信方式。

示例

父组件

<template>
  <div>
    <child-component></child-component>
  </div>
</template>

<script>
export default {
  provide: {
    message: 'hello world'
  }
}
</script>

子组件

<template>
  <div>{{ message }}</div>
</template>

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

九、组件间通信9: Vuex

Vuex 是 Vue 的官方状态管理库,它提供了一种集中式存储管理应用所有组件的状态的方法。

注意点:

  • Vuex 适合大型应用程序,对于小型应用程序可能增加额外的复杂性和开销。
  • 使用 Vuex 时,确保其模式,如 state、mutations、actions 和 getters。
  • 了解 Vuex 的核心概念,如 state、mutations、actions 和 getters。

示例

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  count: 0
}

const mutations = {
  increment (state) {
    state.count++
  },
  decrement (state) {
    state.count--
  }
}

const actions = {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

const getters = {
  doubleCount (state) {
    return state.count * 2
  }
}

export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters
})

App.vue 组件

<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <p>Double Count: {{ $store.getters.doubleCount }}</p>
    <button @click="$store.commit('increment')">Increment</button>
    <button @click="$store.commit('decrement')">Decrement</button>
    <button @click="$store.dispatch('incrementAsync')">Increment Async</button>
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: mapState({
    count: state => state.count
  })
}
</script>

结语

写到这差不多了,能看到这里的还请给自己和博主一个赞吧!

413x299.png