首页 前端知识 【Vue】父组件子组件的通信方式20种(全网最全总结)

【Vue】父组件子组件的通信方式20种(全网最全总结)

2024-06-04 10:06:56 前端知识 前端哥 674 706 我要收藏

目录

一、常用

Props

父组件:

子组件:

$emit和$on

父组件:

子组件:

$parent和$children

父组件:

子组件:

$attrs和$listeners

父组件:

子组件:

provide和inject

父组件:

子组件:

二、其他探索

EventBus

父组件:

子组件:

Vuex

store.js:

父组件:

子组件:

$refs属性

父组件:

子组件:

$parent属性

父组件:

子组件:

$root属性

根组件:

子组件:

provide / inject (高级)

祖先组件:

直接子组件:

间接子组件:

provide / inject + Vuex (高级)

根组件:

子组件和孙组件:

自定义事件

父组件:

子组件:

兄弟组件之间的通信

EventBus.js:

组件A:

组件B:

localStorage(浏览器缓存)

组件A:

组件B:

发布订阅(Pub/Sub)模式

消息中心:

组件A:

组件B:

WebSocket (高级)

连接WebSocket服务器:

组件A:

组件B:

路由参数(高级)

父组件:

子组件:

兄弟组件:

Vuex状态管理(高级)

store.js:

组件A:

组件B:

事件总线(高级)

事件总线:

组件A:

组件B:

三、往期优质推荐


一、常用

  • 最近一直在封装各种组件, 提高组员开发效率,
  • 遇到了各种情况下的父子组件, 兄弟组件之间各种传值,
  • 这里做下总结和一些探索, 欢迎补充~

Props

父组件向子组件传递数据,子组件通过props属性接收数据

父组件:

<template>
  <div>
    <child-component :parentData="data"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  data () {
    return {
      data: '父组件传递的数据'
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ parentData }}
  </div>
</template>

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

Vue props默认值类型有哪些

$emit和$on

子组件向父组件传递数据,子组件通过$emit触发事件,父组件通过$on监听事件并接收数据。

父组件:

<template>
  <div>
    <child-component @childEvent="handleChild"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleChild (data) {
      console.log('父组件接收到的数据:' + data)
    }
  }
}
</script>

子组件:

<template>
  <div>
    <button @click="handleClick">点击触发事件</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick () {
      this.$emit('childEvent', '子组件传递的数据')
    }
  }
}
</script>

$parent和$children

父组件向子组件传递数据,父组件通过$children获取子组件实例并调用子组件方法传递数据。

父组件:

<template>
  <div>
    <button @click="handleClick">向子组件传递数据</button>
    <child-component ref="child"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleClick () {
      this.$refs.child.handleData('父组件传递的数据')
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件
  </div>
</template>

<script>
export default {
  methods: {
    handleData (data) {
      console.log('子组件接收到的数据:' + data)
    }
  }
}
</script>

$attrs和$listeners

父组件向子组件传递属性和事件,子组件通过$attrs获取属性,通过$listeners获取事件并绑定在子组件上。

父组件:

<template>
  <div>
    <child-component attr1="属性1" attr2="属性2" @event1="handleEvent"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleEvent (data) {
      console.log('父组件接收到的数据:' + data)
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件
  </div>
</template>

<script>
export default {
  mounted () {
    this.$emit('event1', '子组件传递的数据')
  }
}
</script>

provide和inject

父组件向子组件传递数据,父组件通过provide提供数据,子组件通过inject注入数据。

父组件:

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

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

export default {
  components: {
    ChildComponent
  },
  provide () {
    return {
      parentData: '父组件提供的数据'
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ childData }}
  </div>
</template>

<script>
export default {
  inject: ['parentData'],
  computed: {
    childData () {
      return this.parentData + ',子组件加工处理后的数据'
    }
  }
}
</script>

二、其他探索

EventBus

父组件和子组件之间通过中央事件总线(EventBus)进行通信。

EventBus.js:

import Vue from 'vue'
export const EventBus = new Vue()

父组件:

<template>
  <div>
    <button @click="handleParent">向子组件传递数据</button>
    <child-component></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'
import { EventBus } from './EventBus'

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleParent () {
      EventBus.$emit('parent-event', '父组件传递的数据')
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ childData }}
  </div>
</template>

<script>
import { EventBus } from './EventBus'

export default {
  data () {
    return {
      childData: ''
    }
  },
  mounted () {
    EventBus.$on('parent-event', data => {
      this.childData = data
    })
  }
}
</script>

Vuex

父组件和子组件之间通过Vuex进行通信,共享同一状态树。

store.js:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    data: '共享的数据'
  },
  mutations: {
    setData (state, data) {
      state.data = data
    }
  }
})

父组件:

<template>
  <div>
    <button @click="handleParent">向子组件传递数据</button>
    <child-component></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleParent () {
      store.commit('setData', '父组件传递的数据')
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ childData }}
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['data']),
    childData () {
      return this.data + ',子组件加工处理后的数据'
    }
  }
}
</script>

$refs属性

父组件可以通过$refs获取子组件的实例,进而访问子组件的属性和方法。

父组件:

<template>
  <div>
    <button @click="handleParent">向子组件传递数据</button>
    <child-component ref="child"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleParent () {
      this.$refs.child.childData = '父组件修改的数据'
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ childData }}
  </div>
</template>

<script>
export default {
  data () {
    return {
      childData: '子组件原始数据'
    }
  }
}
</script>

$parent属性

子组件可以通过$parent获取父组件的实例,进而访问父组件的属性和方法。

父组件:

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

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

export default {
  components: {
    ChildComponent
  },
  data () {
    return {
      parentData: '父组件数据'
    }
  },
  methods: {
    handleParent () {
      console.log('父组件的方法')
    }
  }
}
</script>

子组件:

<template>
  <div>
    <button @click="handleChild">调用父组件方法</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleChild () {
      console.log(this.$parent.parentData)
      this.$parent.handleParent()
    }
  }
}
</script>

$root属性

子组件可以通过$root获取根组件的实例,进而访问根组件的属性和方法。

根组件:

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

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

export default {
  components: {
    ChildComponent
  },
  mounted () {
    console.log('根组件的数据:' + this.rootData)
    this.rootMethod()
  },
  data () {
    return {
      rootData: '根组件的数据'
    }
  },
  methods: {
    rootMethod () {
      console.log('根组件的方法')
    }
  }
}
</script>

子组件:

<template>
  <div>
    子组件
  </div>
</template>

<script>
export default {
  mounted () {
    console.log('根组件的数据:' + this.$root.rootData)
    this.$root.rootMethod()
  }
}
</script>

provide / inject (高级)

provide / inject 可以让祖先组件向所有后代组件注入一个依赖,让这些组件使用相同的依赖注入。

祖先组件:

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

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

export default {
  components: {
    ChildComponent,
    GrandChild
  },
  provide: {
    sharedObj: {
      message: '这是祖先组件注入的对象'
    }
  }
}
</script>

直接子组件:

<template>
  <div>
    子组件
  </div>
</template>

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

间接子组件:

<template>
  <div>
    子组件接收到的数据:{{ childData }}
  </div>
</template>

<script>
export default {
  inject: ['sharedObj'],
  computed: {
    childData () {
      return this.sharedObj.message + ',子组件加工处理后的数据'
    }
  }
}
</script>

provide / inject + Vuex (高级)

使用provide / inject注入Vuex的实例,使所有组件使用相同的Vuex实例。

store.js:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    data: '共享的数据'
  },
  mutations: {
    setData (state, data) {
      state.data = data
    }
  }
})

根组件:

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

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

export default {
  components: {
    ChildComponent
  },
  provide () {
    return {
      store
    }
  }
}
</script>

子组件和孙组件:

<template>
  <div>
    组件接收到的数据:{{ componentData }}
  </div>
</template>

<script>
export default {
  inject: {
    store: {
      default: null
    }
  },
  computed: {
    componentData () {
      return this.store.state.data + ',组件加工处理后的数据'
    }
  }
}
</script>

自定义事件

使用vm.$on(eventName, callback)事件监听,使用vm.$emit(eventName, ...args)触发事件。

父组件:

<template>
  <div>
    <child-component @custom-event="handleCustomEvent"></child-component>
  </div>
</template>

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

export default {
  components: {
    ChildComponent
  },
  methods: {
    handleCustomEvent (data) {
      console.log('父组件接收到的数据:' + data)
    }
  }
}
</script>

子组件:

<template>
  <div>
    <button @click="handleClick">点击触发事件</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick () {
      this.$emit('custom-event', '子组件传递的数据')
    }
  }
}
</script>

兄弟组件之间的通信

使用一个空的Vue实例作为事件总线,一边向事件总线发出事件,另一边监听事件。

EventBus.js:

import Vue from 'vue'
export const EventBus = new Vue()

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
import { EventBus } from './EventBus'

export default {
  methods: {
    handleClick () {
      EventBus.$emit('event', '组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
import { EventBus } from './EventBus'

export default {
  data () {
    return {
      data: ''
    }
  },
  mounted () {
    EventBus.$on('event', data => {
      this.data = data
    })
  }
}
</script>

localStorage(浏览器缓存)

使用浏览器缓存来存储数据,在需要通信的组件中存储并监听缓存中的数据。

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick () {
      localStorage.setItem('data', '组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
export default {
  data () {
    return {
      data: ''
    }
  },
  mounted () {
    window.addEventListener('storage', this.handleStorageUpdate)
    this.updateData()
  },
  beforeDestroy () {
    window.removeEventListener('storage', this.handleStorageUpdate)
  },
  methods: {
    handleStorageUpdate (event) {
      if (event.key === 'data') {
        this.updateData()
      }
    },
    updateData () {
      this.data = localStorage.getItem('data') || ''
    }
  }
}
</script>

发布订阅(Pub/Sub)模式

使用一个消息中心,订阅者向消息中心订阅消息,发布者向消息中心发布消息,消息中心将消息通知给所有订阅者。

消息中心:

// PubSub.js
export const PubSub = {
  events: {},
  subscribe (event, callback) {
    if (!this.events[event]) {
      this.events[event] = []
    }
    this.events[event].push(callback)
  },
  publish (event, data) {
    if (!this.events[event]) {
      this.events[event] = []
    }
    this.events[event].forEach(callback => callback(data))
  }
}

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
import { PubSub } from './PubSub'

export default {
  methods: {
    handleClick () {
      PubSub.publish('event', '组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
import { PubSub } from './PubSub'

export default {
  data () {
    return {
      data: ''
    }
  },
  mounted () {
    PubSub.subscribe('event', data => {
      this.data = data
    })
  }
}
</script>

WebSocket (高级)

使用WebSocket协议实现实时通信,将所有组件连接到同一个WebSocket服务器,通过推送消息实现通信。

连接WebSocket服务器:

const ws = new WebSocket('ws://localhost:3000')

ws.onopen = function () {
  console.log('WebSocket已连接')
}

ws.onclose = function () {
  console.log('WebSocket已关闭')
}

ws.onerror = function () {
  console.log('WebSocket出错')
}

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
const ws = new WebSocket('ws://localhost:3000')

export default {
  methods: {
    handleClick () {
      ws.send('组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
const ws = new WebSocket('ws://localhost:3000')

export default {
  data () {
    return {
      data: ''
    }
  },
  mounted () {
    ws.onmessage = event => {
      this.data = event.data
    }
  }
}
</script>

路由参数(高级)

使用路由参数来传递数据,通常适用于父子组件之间或兄弟组件之间的通信。

父组件:

<template>
  <div>
    点击以下链接可以传递数据:<br>
    <router-link :to="{ name: 'child', params: { data: '父组件传递的数据' } }">传递数据到子组件</router-link>
  </div>
</template>

子组件:

<template>
  <div>
    子组件接收到的数据:{{ $route.params.data }}
  </div>
</template>

<script>
export default {
  mounted () {
    console.log('子组件接收到的数据:' + this.$route.params.data)
  }
}
</script>

兄弟组件:

<template>
  <div>
    兄弟组件接收到的数据:{{ $route.params.data }}
  </div>
</template>

<script>
export default {
  mounted () {
    console.log('兄弟组件接收到的数据:' + this.$route.params.data)
  }
}
</script>

Vuex状态管理(高级)

使用Vuex管理公共状态,组件通过Vuex进行通信。

store.js:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    data: '共享的数据'
  },
  mutations: {
    setData (state, data) {
      state.data = data
    }
  }
})

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
import store from './store'

export default {
  methods: {
    handleClick () {
      store.commit('setData', '组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['data'])
  },
  mounted () {
    console.log('组件B接收到的数据:' + this.data)
  }
}
</script>

事件总线(高级)

使用一个空的Vue实例作为事件总线,组件A通过事件总线向组件B传递数据。

事件总线:

// EventBus.js
import Vue from 'vue'
export const EventBus = new Vue()

组件A:

<template>
  <div>
    <button @click="handleClick">向组件B传递数据</button>
  </div>
</template>

<script>
import { EventBus } from './EventBus'

export default {
  methods: {
    handleClick () {
      EventBus.$emit('event', '组件A传递的数据')
    }
  }
}
</script>

组件B:

<template>
  <div>
    组件B接收到的数据:{{ data }}
  </div>
</template>

<script>
import { EventBus } from './EventBus'

export default {
  data () {
    return {
      data: ''
    }
  },
  mounted () {
    EventBus.$on('event', data => {
      this.data = data
    })
  }
}
</script>

三、往期优质推荐

VSCode 最全实用插件(VIP典藏版)
Vue超详细整理(VIP典藏版)
Vue中created,mounted,updated详解
一文快速上手Echarts(持续更新)
Vue中el-table数据项扩展各种类型总结(持续更新)

有用请点赞,养成良好习惯!

疑问、交流、鼓励请留言!

转载请注明出处或者链接地址:https://www.qianduange.cn//article/10712.html
标签
评论
发布的文章

js-jquery页面跳转集合

2024-06-08 22:06:13

echarts柱状图数据过多

2024-06-08 22:06:31

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!