Vue2.0组件之间的通信方式

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

一、props & $emit

props$emit大概是我们平时用的最多的方式把。父组件向子组件传值采用prop来传递,子组件则用$emit通过事件触发的方式来传递。

父组件

<template>
  <div>
    <div class="parent">
      <div>我是父组件</div>
      <div>{{sonMsg}}</div>
      <SonCom :msg="msg" @onSonSay="onSonSay"></SonCom>
    </div>
    
  </div>
</template>

<script>
import SonCom from './SonCom.vue'
export default {
  components: { SonCom },
  data() {
    return {
      msg: '我是你爸爸',
      sonMsg: ''
    }
  },
  methods: {
    onSonSay(val) {
      this.sonMsg = val
    }
  },
}
</script>

<style>
.parent {
  width: 500px;
  height: 150px;
  border: 1px solid red;
}
</style>
复制代码

子组件

<template>
  <div class="son">
    <div>我是子组件</div>
    <div>
      父组件对子组件说 {{msg}}
    </div>
    <button @click="handleClick">子组件说</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
    }
  },
  props: {
    msg: {
      type: String
    }
  },
  methods: {
    handleClick() {
      this.$emit('onSonSay', '你是我爸爸,你给钱我花啊!')
    }
  },
}
</script>
<style>
.son {
  width: 500px;
  height: 150px;
  border: 1px solid green;
}
</style>
复制代码

image.png

二、ref

我们在父组件里面引入的子组件上面设置ref来获取到组件里面的属性方法

<div @click="onGetSonMsgOnRef">点击我,通过ref来访问子组件数据:{{getSonMsgOnRef}}</div>
<SonCom ref="sonComRef" :msg="msg" @onSonSay="onSonSay"></SonCom>

onGetSonMsgOnRef() {
  this.getSonMsgOnRef = this.$refs.sonComRef.sonMsg
}
复制代码

image.png

三、$parent & $children

  • 子组件通过访问$parent来获取父组件的信息
    <div @click="() => parentMsg = $parent.msg">点击我,通过$parent拿到父组件的数据:{{parentMsg}}</div>
复制代码
  • 父组件通过$children来访问子组件的信息。
<div @click="() => childrenMsg = $children[0].sonMsg">点击我,通过$children拿到子组件的数据:{{childrenMsg}}</div>
复制代码

image.png

四、provide & inject

provideinject可以实现祖孙组件间的通信。祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。

新建一个GrandsonCom组件

<template>
  <div>
    <h3>{{grandson}}</h3>
    <div>我通过inject拿到爷爷组件信息:{{name}}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      grandson: '我是孙子组件'
    }
  },
  inject: ['name']
}
</script>
复制代码

ParentCom组件中引入孙子组件以及

provide: {
    name: 'parent的数据'
},
复制代码

image.png

五、$attrs$listeners

$attrs$listeners也是可以实现祖孙组件间通信,当组件嵌套过深且中间组件不需要时,可以使用该方式。

  • $attrs

包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

  • $listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

ParentCom.vue

<template>
  <div>
    <div class="parent">
      <div>我是父组件</div>
      <div>{{sonMsg}}</div>
      <div @click="onGetSonMsgOnRef">点击我,通过ref来访问子组件数据:{{getSonMsgOnRef}}</div>
      <div @click="() => childrenMsg = $children[0].sonMsg">点击我,通过$children拿到子组件的数据:{{childrenMsg}}</div>
      <SonCom ref="sonComRef" :msg="msg" :attrs1="attrs1" :attrs2="attrs2" :attrs3="attrs3"
        @onSonSay="onSonSay" v-on:onListeners1="onListeners1" v-on:onListeners2="onListeners2" v-on:onListeners3="onListeners3"
      ></SonCom>
      <!-- <GrandsonCom></GrandsonCom> -->
    </div>
    
  </div>
</template>

<script>
import SonCom from './SonCom.vue'
// import GrandsonCom from './GrandsonCom.vue'
export default {
  components: { SonCom },
  provide: {
    name: 'parent的数据'
  },
  data() {
    return {
      msg: '我是你爸爸',
      sonMsg: '',
      childrenMsg: '',
      getSonMsgOnRef: '',
      attrs1: 'attrs1',
      attrs2: 'attrs2',
      attrs3: 'attrs3'
    }
  },
  methods: {
    onSonSay(val) {
      this.sonMsg = val
    },

    onGetSonMsgOnRef() {
      this.getSonMsgOnRef = this.$refs.sonComRef.sonMsg
    },

    onListeners1() {
      console.log(111, 'onListeners1')
    },

    onListeners2() {
      console.log(222, 'onListeners2')
    },

    onListeners3() {
      console.log(333, 'onListeners3')
    }
  },
}
</script>

<style>
.parent {
  width: 500px;
  min-height: 150px;
  border: 1px solid red;
}
</style>
复制代码

SonCom.vue

<template>
  <div class="son">
    <div>我是子组件</div>
    <div>
      父组件对子组件说 {{msg}}
    </div>
    <button @click="handleClick">子组件说</button>
    <div @click="() => parentMsg = $parent.msg">点击我,通过$parent拿到父组件的数据:{{parentMsg}}</div>
    <div>父组件$attrs来的 {{attrs1}}</div>
     <!-- v-bind="$attrs"通常和interitAttrs 选项一起使用 -->
    <GrandsonCom v-bind="$attrs" v-on="$listeners"></GrandsonCom>
  </div>
</template>

<script>
import GrandsonCom from './GrandsonCom.vue'
export default {
  components: { GrandsonCom },
  data() {
    return {
      sonMsg: '我是子组件里面的数据',
      parentMsg: ''
    }
  },
  inheritAttrs: false,
  props: {
    msg: {
      type: String
    },
    attrs1: {
      type: String
    }
  },
  methods: {
    handleClick() {
      console.log(this.$parent)
      this.$emit('onSonSay', '你是我爸爸,你给钱我花啊!')
    }
  },
  mounted() {
    this.$emit('onListeners1')
  },
}
</script>
<style>
.son {
  width: 500px;
  min-height: 150px;
  border: 1px solid green;
}
</style>
复制代码

GrandsonCom.vue

<template>
  <div>
    <h3>{{grandson}}</h3>
    <div>我通过inject拿到爷爷组件信息:{{name}}</div>
    <div>爷爷组件来的attrs: {{attrs2}} </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      grandson: '我是孙子组件'
    }
  },
  inject: ['name'],
  props: ['attrs2'],
  mounted() {
    console.log('grandson attrs', this.$attrs)
    this.$emit('onListeners2')
  },
}
</script>
复制代码

image.png

六、事件总线EventBus

首先我们创建一个event-bus.js文件

import Vue from 'vue'
export const EventBus = new Vue()
复制代码

然后我们创建一个OtherCom.vue文件,并在在App.vue文件中引入

<template>
  <div>
    <div>{{msg}}</div>
    <div>{{eventBusMsg}}</div>
  </div>
</template>

<script>
import { EventBus } from "../event-bus.js";
export default {
  data() {
    return {
      msg: '我是一个毫无关系的组件',
      eventBusMsg: ''
    }
  },
  mounted() {
    EventBus.$on('onEventBus', (msg) => {
      this.eventBusMsg = msg
    })
  },
}
</script>
复制代码

我们在ParentCom.vue中引入event-bus.js文件,添加如下代码

<button @click="onSendMsg">发送公共消息</button>

onSendMsg() {
  EventBus.$emit('onEventBus', '来自父组件的消息');
}
复制代码

image.png 点击父组件页面发送公共消息按钮,会看到'来自父组件的消息'在页面上显示出来。

你可以使用 EventBus.$off('onEventBus') 来移除应用内所有对此某个事件的监听。或者直接调用 EventBus.$off() 来移除所有事件频道,不需要添加任何参数 。

七、vuex

vuex也可以实现跨组件通信,这里就不多说了,后面也会更新vuex相关的文章。

八、本地缓存的方式

可以使用localStorage 和 sessionStorage,可以实现跨组件通信。

猜你喜欢

转载自juejin.im/post/7067083542743744525