在 Vue.js 3 中,组件通信主要包括父子组件通信、兄弟组件通信以及祖孙组件通信。以下是各种情况下的常见通信方式:

1. 父子组件通信

1.1 Props 传递数据:

父组件通过 props 向子组件传递数据:

<!-- Parent.vue -->
<template>
  <Child :message="parentMessage" />
</template>

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

export default {
  data() {
    return {
      parentMessage: 'Hello from Parent!'
    };
  },
  components: {
    Child
  }
};
</script>

<!-- Child.vue -->
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: ['message']
};
</script>
1.2 事件监听子组件:

子组件通过 $emit 触发事件,父组件通过监听这些事件来响应:

<!-- Parent.vue -->
<template>
  <Child @notifyParent="handleNotify" />
</template>

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

export default {
  methods: {
    handleNotify(message) {
      console.log(message); // 处理从子组件传递的数据
    }
  },
  components: {
    Child
  }
};
</script>

<!-- Child.vue -->
<template>
  <button @click="notifyParent">Notify Parent</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      this.$emit('notifyParent', 'Hello from Child!');
    }
  }
};
</script>
1.3 definEexpose暴露子组件方法

在 Vue 3 中,使用 TypeScript 编写组件时,如果想要将子组件的方法暴露给父组件,可以使用 defineExpose 函数。defineExpose 允许你定义哪些内容应该被暴露给父组件,以供父组件访问。

下面是一个简单的例子,演示如何在子组件中使用 defineExpose 暴露方法:

// ChildComponent.vue
<template>
  <div>
    <button @click="incrementCounter">Increment Counter</button>
  </div>
</template>

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

const counter = ref(0);

const incrementCounter = () => {
  counter.value++;
};

// 暴露方法给父组件
defineExpose({
  incrementCounter
});
</script>

在这个例子中,incrementCounter 方法被定义在子组件中,并通过 defineExpose 函数进行了暴露。父组件可以通过子组件的引用来调用这个方法。

// ParentComponent.vue
<template>
  <div>
    <ChildComponent ref="childRef" />
    <button @click="callChildMethod">Call Child Method</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const childRef = ref();

const callChildMethod = () => {
  // 调用子组件的方法
  childRef.value.incrementCounter();
};
</script>

在父组件中,通过 ref 引用子组件,然后可以调用子组件中暴露的方法。

这样,通过 defineExpose 可以在 Vue 3 中很方便地实现子组件方法的暴露。这对于构建可重用组件库或复杂组件通信场景非常有用。

$attrs批量绑定子组件事件

$attrs 是 Vue.js 中的一个属性,它在 Vue 2.4.0 及以后的版本中引入,并且在 Vue 3 中仍然保留,但其功能有所增强。$attrs 主要用于在组件之间传递未被子组件声明的属性(attributes)。

使用场景:

  1. 二次封装组件:当你想要封装一个组件,并希望将父组件传递给该组件的所有属性(除了已经作为 props 声明或自定义事件声明的属性)都传递给子组件时,可以使用 $attrs。这样,你就不需要手动一一传递这些属性,而是直接通过 $attrs 一次性传递。
  2. 多层嵌套组件:在多层嵌套的组件结构中,如果你想要将数据从顶层组件传递到深层的子组件,而不需要在每一层都使用 props 进行传递,那么 $attrs 可以帮助你实现这一需求。你只需要在顶层组件中一次性将数据作为属性传递给中间的包装组件,然后在包装组件中使用 $attrs 将这些属性传递给它的子组件,以此类推,直到数据最终到达目标子组件。

使用方法

在模板中,你可以使用 v-bind 指令将 $attrs 绑定到子组件上,如下所示:

<template>
  <div>
    <child-component v-bind="$attrs"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  }
  // ... 其他选项
};
</script>

在上面的示例中,<child-component> 会接收到父组件传递的所有未被子组件声明的属性。

注意事项

  • $attrs 不包括 classstyle 属性,因为这两个属性有特殊的处理机制。
  • 在 Vue 3 中,$attrs 还包含了父组件的事件监听器(即 Vue 2 中的 $listeners),因此你可以使用 $attrs 来同时传递属性和事件监听器。
  • 如果子组件已经声明了某个属性作为 prop,那么该属性将不会包含在 $attrs 中,因为它已经被子组件识别并处理。

2. 兄弟组件通信

2.1 通过共享状态(使用父组件):

通过将状态提升到共同的父组件,然后通过 props 和事件来实现兄弟组件之间的通信。

2.2 使用事件总线(Bus):

创建一个事件总线,兄弟组件通过事件总线来通信。在 Vue 3 中,可以使用 provide/inject 来创建一个简单的事件总线。

// EventBus.js
import { createApp, ref } from 'vue';

const bus = createApp();
bus.provide('eventBus', bus);

// ComponentA.vue
<script>
export default {
  methods: {
    notifySibling() {
      this.$root.eventBus.emit('siblingEvent', 'Hello from Component A!');
    }
  }
};
</script>

// ComponentB.vue
<script>
export default {
  created() {
    this.$root.eventBus.on('siblingEvent', message => {
      console.log(message); // 处理从兄弟组件传递的数据
    });
  }
};
</script>

3. 祖孙组件通信

3.1 通过 provide/inject:

使用 provide/inject 可以实现祖孙组件之间的通信,祖先组件通过 provide 提供数据,孙子组件通过 inject 获取数据。

<!-- Grandparent.vue -->
<template>
  <Parent />
</template>

<script>
import { ref } from 'vue';
import Parent from './Parent.vue';

export default {
  setup() {
    const grandparentMessage = ref('Hello from Grandparent!');

    provide('grandparentMessage', grandparentMessage);

    return {
      grandparentMessage
    };
  },
  components: {
    Parent
  }
};
</script>

<!-- Parent.vue -->
<template>
  <Child />
</template>

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

export default {
  components: {
    Child
  }
};
</script>

<!-- Child.vue -->
<template>
  <div>{{ grandparentMessage }}</div>
</template>

<script>
import { inject } from 'vue';

export default {
  setup() {
    const grandparentMessage = inject('grandparentMessage');
    return {
      grandparentMessage
    };
  }
};
</script>

4. Vuex(全局状态管理)

如果你的应用中需要管理全局状态,Vuex 是一个强大的状态管理库。通过将状态存储在 Vuex 中,不同组件可以通过 Vuex 的 store 来实现通信。

// store.js
import { createStore } from 'vuex';

export default createStore({
  state: {
    message: 'Hello from Vuex!'
  },
  mutations: {
    updateMessage(state, newMessage) {
      state.message = newMessage;
    }
  },
  actions: {
    changeMessage({ commit }, newMessage) {
      commit('updateMessage', newMessage);
    }
  }
});

// ComponentA.vue
<script>
export default {
  computed: {
    message() {
      return this.$store.state.message;
    }
  },
  methods: {
    changeMessage() {
      this.$store.dispatch('changeMessage', 'New Message');
    }
  }
};
</script>

// ComponentB.vue
<script>
export default {
  computed: {
    message() {
      return this.$store.state.message;
    }
  }
};
</script>

在 Vue.js 生态系统中,除了 Vuex 之外,还有一些其他状态管理库,其中包括 Pinia 和 Tini。这两个库提供了不同的方式来处理状态管理,和 Vuex 一样,它们都是 Vue 3 的状态管理库。

5. Pinia

Pinia 是一个由 Vue.js 团队开发的状态管理库,旨在提供简单、灵活且性能出色的状态管理方案。与 Vuex 不同,Pinia 使用了更现代的 API,并且是基于 Composition API 构建的。

Pinia 的特点:

  • 使用 Composition API 构建。
  • 具有 TypeScript 支持。
  • 基于 Vue 3 的响应式系统。
  • 使用插件系统轻松扩展功能。

安装 Pinia:

npm install pinia

使用 Pinia:

import { createPinia } from 'pinia';

const pinia = createPinia();

export const useStore = pinia.createStore({
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.state.count++;
    }
  }
});

6.mitt

mitt 是一个简单而小巧的事件总线库,用于在应用程序的不同部分之间进行事件通信。它提供了一种简单的方式来发射和监听事件。与 Vuex 的 $emit$on 类似,但 mitt 更为轻量。

下面是 mitt 的基本用法:

import mitt from 'mitt';

// 创建事件总线
const emitter = mitt();

// 监听事件
emitter.on('custom-event', (data) => {
  console.log('Event Received:', data);
});

// 发射事件
emitter.emit('custom-event', 'Hello from Mitt!');

在上面的代码中,emitter 是一个事件总线实例,可以用于在不同部分之间发送和接收事件。

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐