服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - vue.js - Vue3.js组件通信,兄弟组件、父子、祖孙组件间通信

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

2024-01-09 14:01海燕技术栈 vue.js

在 Vue.js 3 中,组件通信主要包括父子组件通信、兄弟组件通信以及祖孙组件通信。以下是各种情况下的常见通信方式: 1. 父子组件通信: 1.1 Props 传递数据: 父组件通过 props 向子组件传递数据: !-- Parent.vue --template Child :message

在 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 中很方便地实现子组件方法的暴露。这对于构建可重用组件库或复杂组件通信场景非常有用。

$listeners批量绑定子组件事件

$listeners 是一个对象,包含了父组件传递给子组件的所有事件监听器。这个对象允许子组件将所有未被自身处理的事件监听器绑定到合适的 HTML 元素上。

通常情况下,当你在子组件中使用 v-on="$listeners" 时,它会将所有的父组件传递下来的事件监听器应用到相应的 DOM 元素上。

以下是一个简单的例子,演示了 $listeners 的使用:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent @custom-event="handleCustomEvent" />
</template>


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


export default {
  methods: {
    handleCustomEvent(data) {
      console.log('Custom Event Handled in Parent:', data);
    }
  },
  components: {
    ChildComponent
  }
};
</script>
<!-- ChildComponent.vue -->
<template>
  <div>
    <button @click="triggerCustomEvent">Trigger Custom Event</button>
  </div>
</template>


<script>
export default {
  methods: {
    triggerCustomEvent() {
      // 触发自定义事件并传递数据
      this.$emit('custom-event', 'Hello from Child');
    }
  }
};
</script>

在子组件中,当用户点击按钮时,触发了一个自定义事件,并通过 $emit 传递了数据给父组件。如果你希望在父组件中使用该事件监听器,可以通过 $listeners 将其传递到子组件的相应元素上:

<!-- ChildComponent.vue -->
<template>
  <div>
    <button @click="triggerCustomEvent" v-on="$listeners">Trigger Custom Event</button>
  </div>
</template>


<script>
export default {
  methods: {
    triggerCustomEvent() {
      // 触发自定义事件并传递数据
      this.$emit('custom-event', 'Hello from Child');
    }
  }
};
</script>

现在,在父组件中,你可以监听子组件触发的 custom-event 事件:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent @custom-event="handleCustomEvent" />
</template>


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


export default {
  methods: {
    handleCustomEvent(data) {
      console.log('Custom Event Handled in Parent:', data);
    }
  },
  components: {
    ChildComponent
  }
};
</script>

在这个例子中,v-on="$listeners" 将所有父组件传递的事件监听器应用到了按钮上,这样子组件就能够触发相应的事件并将数据传递给父组件。

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 生态系统中,除了 $listeners 之外,还有一些其他状态管理库,其中包括 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 是一个事件总线实例,可以用于在不同部分之间发送和接收事件。

原文地址:https://mp.weixin.qq.com/s/iN4AAcrQHxHUZkz1tJp3ug

延伸 · 阅读

精彩推荐
  • vue.jsVue router-view和router-link的实现原理

    Vue router-view和router-link的实现原理

    这篇文章主要介绍了Vue router-view和router-link的实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    mengyuhang48794492022-02-13
  • vue.jsvue 实现删除对象的元素 delete

    vue 实现删除对象的元素 delete

    这篇文章主要介绍了vue 实现删除对象的元素delete,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    vue学习3702022-08-17
  • vue.jsvue浏览器返回监听的具体步骤

    vue浏览器返回监听的具体步骤

    这篇文章主要给大家介绍了关于vue浏览器返回监听的具体步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    不求甚解bc10552022-01-17
  • vue.jsVUE+Express+MongoDB前后端分离实现一个便签墙

    VUE+Express+MongoDB前后端分离实现一个便签墙

    这篇文章主要介绍了VUE+Express+MongoDB前后端分离实现一个便签墙,需要的朋友可以参考下...

    登楼痕5682022-03-05
  • vue.jsVue实现简易购物车页面

    Vue实现简易购物车页面

    这篇文章主要为大家详细介绍了Vue实现简易购物车页面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    小王同学Max4982021-12-22
  • vue.jsvue.js集成echarts时遇到的一些问题总结

    vue.js集成echarts时遇到的一些问题总结

    这篇文章主要给大家总结介绍了关于vue.js集成echarts遇到的一些问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    beetlex9252022-02-28
  • vue.jsvue仿携程轮播图效果(滑动轮播,下方高度自适应)

    vue仿携程轮播图效果(滑动轮播,下方高度自适应)

    这篇文章主要介绍了vue仿携程轮播图效果(滑动轮播,下方高度自适应),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要...

    牛顿顿的apple11762022-01-20
  • vue.jsvue cli3 实现分环境打包的步骤

    vue cli3 实现分环境打包的步骤

    这篇文章主要介绍了vue cli3 实现分环境打包的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的...

    水帅杰12002022-02-16