vue组件间通信的四种方法

0 四种方式

  1. 父子传参
  2. 事件总线 bus
  3. provided/injected
  4. Vuex

1 父子组件通信

父传子props, 子传父$emit

2 兄弟

通过父组件转发

老大->父组件->老二 (单向)

  • One.vue 老大提交自定义事件
<template>
  <div>
    老大子组件:
    <input type="text" v-model="msg" />
    <button @click="$emit('send',msg)">发送</button>
  </div>
</template>

<script>
export default {
  name: 'One',
  data() {
    return { msg: '' }
  },
}
</script>
  • Two.vue 老二接收参数
<template>
  <div>老二子组件: {{ msg }}</div>
</template>

<script>
  export default {
    name: 'Two',
    props: {
      msg: { type: String },
    },
  }
</script>
  • App.vue 父组件监听自定义事件
<template>
  <div id="app">
    <one @send="handleSend"></one>
    <two :msg="msg"></two>
  </div>
</template>

<script>
import One from './components/One.vue'
import Two from './components/Two.vue'

  export default {
    name: 'App',
    components: {
      One,
      Two,
    },
    data() {
      return {
        msg: '',
      }
    },
    methods: {
      handleSend(msg) {
        this.msg = msg
      },
    },
  }
</script>

3 表兄弟

3.1 介绍

全局事件总线bus (适合两个组件间通信, 没有明显关系的两个组件)

所有的组件都通过一个统一的全局对象通信

多个组件, 用vuex

3.2 事件总线用法

  • bus/index.js
import Vue from 'vue'

// 这是一个Vue实例对象
const bus = new Vue()

export default bus
  •  Counter.vue 发
<template>
  <div>
    <button @click="handleClick">向Test发送消息</button>
  </div>
</template>

<script>
import bus from '@/bus'

export default {
  name: 'Counter',
  data() {
    return { 
      msg: '',
    }
  },
  methods: {
    handleClick() {
      // 在一个组件中触发事件
      bus.$emit('send', this.msg)
    },
  },
}
</script>
  •  Test.vue 收
<template>
  <div>
    从counter中收到的消息 {{ msg }}
  </div>
</template>

<script>
import bus from '@/bus'
  
export default {
  name: 'Test',
  data() { return { msg: '' } },
  mounted() {
    // 监听自定义事件
    bus.$on('send', (value) => {
      this.msg = value
    })
  },
  beforeDestroy() {
    // 移除自定义事件
    bus.$off('send')
  },
}
</script>

4 祖孙组件通信

依赖注入 provided/injected (vue3直接是响应式)

1) 传静态数据

        1) 在祖先组件中通过 provid选项提供数据

        2) 在后代组件中通过injection选项注入数据

  •  App.vue
// 父级组件提供 'foo'
export default {
  name: 'App',
  provide: {
    foo: 'hello'
  },
  // ...
}
  • son.vue 
// 孙子组件注入 'foo'
export default {
  name: 'Son',
  inject: ['foo'],
  created () {
    console.log(this.foo) 
  }
}

2) 传响应式数据

传入对象

  • App.vue 
<template>
  <div id="app">
    <input type="text" v-model="obj.msg" />
  </div>
</template>

<script>
export default {
  name: 'App',
  provide() {
    return { foo: this.obj }
  },
  data() { return { obj: { msg: '' } } },
}
</script>
  • son.vue 
<template>
  <div>{{ foo.msg }}</div>
</template>

<script>
export default {
  name: 'Son',
  inject: ['foo'],
}
</script>

传入函数

  •  App.vue
<template>
  <div id="app">
    <input type="text" v-model="msg" />
    <counter></counter>
    <test></test>
  </div>
</template>

<script>
export default {
  name: 'App',
  provide() {
    // provide设置为一个函数, 该函数中this指向vm实例
    return { foo: () => this.msg }
  },
  data() { return { msg: '' } },
}
</script>
  •  son.vue
<template>
  <div>{{ foo() }}</div>
</template>

<script>
export default {
  name: 'Son',
  inject: ['foo'],
}
</script>