Vue3.js组件通信,兄弟组件,父子、祖孙组件

本文详细介绍了Vue.js3中组件间的三种主要通信方式:父子组件通过Props传递数据、事件监听与定义暴露子组件方法,以及利用$attrs、事件总线如Vuex、Pinia和mitt进行兄弟组件和祖孙组件通信。同时提及了状态管理的最佳实践,如Vuex和轻量级的mitt库。
摘要由CSDN通过智能技术生成

在 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 是一个事件总线实例,可以用于在不同部分之间发送和接收事件。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3中,可以使用Props和Events来实现祖孙组件之间的传值。 1. Props:父组件可以通过props将数据传递给子组件。在子组件中,可以通过props选项接收这些数据。具体步骤如下: 父组件: ```vue <template> <div> <ChildComponent :message="message" /> </div> </template> <script> import ChildComponent from './ChildComponent' export default { components: { ChildComponent }, data() { return { message: 'Hello from parent component' } } } </script> ``` 子组件: ```vue <template> <div> <p>{{ message }}</p> </div> </template> <script> export default { props: ['message'] } </script> ``` 在父组件中,使用冒号(:)绑定属性,并将数据传递给子组件。子组件中通过props选项接收这个属性。 2. Events:子组件可以通过事件将数据传递给父组件。在子组件中,可以使用$emit方法触发一个自定义事件,并传递数据给父组件。具体步骤如下: 父组件: ```vue <template> <div> <ChildComponent @update-message="updateMessage" /> <p>{{ message }}</p> </div> </template> <script> import ChildComponent from './ChildComponent' export default { components: { ChildComponent }, data() { return { message: '' } }, methods: { updateMessage(newMessage) { this.message = newMessage } } } </script> ``` 子组件: ```vue <template> <div> <button @click="sendMessage">Send Message</button> </div> </template> <script> export default { methods: { sendMessage() { this.$emit('update-message', 'Hello from child component') } } } </script> ``` 在子组件中,使用@click绑定一个点击事件,并在事件处理程序中使用this.$emit方法触发自定义事件。父组件中通过@update-message监听这个事件,并在对应的事件处理函数中更新父组件的数据。 这样就实现了祖孙组件之间的传值。父组件通过props将数据传递给子组件,子组件通过事件将数据传递给父组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值