Vue组件通讯有哪些方式?

278 阅读2分钟

Vue组件通讯有哪些方式?

在Vue开发中,组件通讯是非常重要的一部分。Vue提供了多种方式让组件之间进行通讯。下面我们将介绍几种常用的方式。

Props

Props 是父组件向子组件传递数据的一种方式,父组件可以通过 prop 的方式将数据传递给子组件,子组件则可以在 props 中定义接收的数据。这种方式下,子组件只能读取不可修改父组件的数据。

html复制代码
<!-- 父组件 -->
<template>
  <child-component :name="name" :age="age"></child-component>
</template>

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

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent,
  },
  data() {
    return {
      name: '张三',
      age: 18,
    };
  },
};
</script>

<!-- 子组件 -->
<template>
  <div>
    姓名:{{ name }}
    年龄:{{ age }}
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    name: String,
    age: Number,
  },
};
</script>

emit/emit / on

emitemit 和 on 可以实现子组件向父组件传递数据的功能。子组件通过 $emit 方法触发一个自定义事件,父组件则在模板中通过 v-on 指令监听该事件并执行相应的方法。

html复制代码
<!-- 父组件 -->
<template>
  <child-component @update-name="handleUpdateName"></child-component>
  <div>姓名:{{ name }}</div>
</template>

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

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent,
  },
  data() {
    return {
      name: '张三',
    };
  },
  methods: {
    handleUpdateName(name) {
      this.name = name;
    },
  },
};
</script>

<!-- 子组件 -->
<template>
  <div>
    <input type="text" v-model="name" />
    <button @click="updateName">更新姓名</button>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  data() {
    return {
      name: '',
    };
  },
  methods: {
    updateName() {
      this.$emit('update-name', this.name);
    },
  },
};
</script>

parent/parent / children

parentparent 和 children 可以实现父子组件之间的直接通讯。可以通过 parent获取父组件的实例,通过parent 获取父组件的实例,通过 children 获取子组件的实例。

html复制代码
<!-- 父组件 -->
<template>
  <child-component></child-component>
</template>

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

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent,
  },
  methods: {
    handleChild() {
      console.log(this.$children[0].msg);
      this.$children[0].show();
    },
  },
};
</script>

<!-- 子组件 -->
<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: 'ChildComponent',
  data() {
    return {
      msg: 'Hello, Vue!',
    };
  },
  methods: {
    show() {
      alert(this.msg);
    },
  },
};
</script>

$refs

$refs 可以给组件或者 HTML 元素添加一个唯一的标识,通过这个标识可以在父组件中访问子组件或者 HTML 元素的实例。

html复制代码
<!-- 父组件 -->
<template>
  <child-component ref="myChildComponent"></child-component>
  <button @click="handleClick">调用子组件方法</button>
</template>

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

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent,
  },
  methods: {
    handleClick() {
      this.$refs.myChildComponent.show();
    },
  },
};
</script>

<!-- 子组件 -->
<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: 'ChildComponent',
  data() {
    return {
      msg: 'Hello, Vue!',
    };
  },
  methods: {
    show() {
      alert(this.msg);
    },
  },
};
</script>

Vuex

Vuex 是一种专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

通过在组件中使用 $store 访问全局状态,组件就可以获取和修改全局状态数据。

html复制代码
<!-- 父组件 -->
<template>
  <div>计数器:{{ count }}</div>
  <button @click="handleIncrement">+1</button>
</template>

<script>
import { mapState, mapMutations } from 'vuex';

export default {
  name: 'ParentComponent',
  computed: {
    ...mapState(['count']),
  },
  methods: {
    ...mapMutations(['increment']),
    handleIncrement() {
      this.increment();
    },
  },
};
</script>

<!-- store -->
<script>
import Vuex from 'vuex';
import Vue from 'vue';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0,
  },
  mutations: {
    increment(state) {
      state.count++;
    },
  },
});

export default store;
</script>

以上是 Vue 组件通讯的几种常用方式,开发者可以根据实际需求选择合适的方式。此外,还有一些其他的通讯方式,例如:

$bus

使用 bus可以实现非父子组件之间的通讯。可以在Vue实例中创建一个空的Vue实例用作事件总线,在需要通讯的组件中通过bus 可以实现非父子组件之间的通讯。可以在 Vue 实例中创建一个空的 Vue 实例用作事件总线,在需要通讯的组件中通过 emit 和 $on 方法触发和监听自定义事件。

html复制代码
<!-- 组件A -->
<template>
  <button @click="handleClick">点击发送消息</button>
</template>

<script>
export default {
  name: 'ComponentA',
  methods: {
    handleClick() {
      this.$bus.$emit('send-message', 'Hello, World!');
    },
  },
};
</script>

<!-- 组件B -->
<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: 'ComponentB',
  data() {
    return {
      msg: '',
    };
  },
  created() {
    this.$bus.$on('send-message', (msg) => {
      this.msg = msg;
    });
  },
};
</script>

<!-- Vue实例 -->
<script>
import Vue from 'vue';

export default {
  name: 'App',
  beforeCreate() {
    Vue.prototype.$bus = new Vue();
  },
};
</script>

provide / inject

provide 和 inject 是一种高级特性,可以实现祖先组件向后代组件传递数据的功能。祖先组件通过 provide 方法提供数据,后代组件则通过 inject 方法注入数据。

html复制代码
<!-- 祖先组件 -->
<template>
  <child-component></child-component>
</template>

<script>
export default {
  name: 'AncestorComponent',
  provide() {
    return {
      name: '张三',
    };
  },
};
</script>

<!-- 后代组件 -->
<template>
  <div>{{ name }}</div>
</template>

<script>
export default {
  name: 'ChildComponent',
  inject: ['name'],
};
</script>

以上是 Vue 组件通讯的常用方式,开发者可以根据不同场景选择合适的方法。在实际开发中,可能会结合多种方式进行通讯,例如使用 Props 传递数据 + $emit 触发事件更新父组件状态。最后,我们需要注意的是,在组件通讯中避免滥用事件总线、全局状态等方式,因为这些方式可能会导致数据流不可控、难以维护。在设计组件时需要考虑到数据的传递和共享,并在合适的层级上进行管理。

另外,Vue 3 中也提供了一些新的 API 来实现更加灵活和高效的组件通讯,例如 setup() 函数中的 props 和 context 参数、teleport 组件等。开发者可以关注 Vue 3 的更新文档来了解更多信息。

总而言之,Vue 提供了丰富的组件通讯方式,开发者需要根据实际需求并结合最佳实践进行选择和使用,以便开发出高质量、易于维护的应用程序