组件间通信

141 阅读3分钟

组件数据传递

为了清楚地说明组件间传递关系,以思特奇大学为例:Sitech组件为Exam和Lesson组件地父组件,Exam和Lesson组件为兄弟组件。

一、 props传递

  1. 父组件向子组件传值 在父组件调用子组件时,为子组件添加属性参数,子组件通过props进行接收,这是最简单方便的一种传值方式,实现如下图。
    父组件代码: <button @click="getExamName">从父组件获取名字</button>
    子组件代码:
<button @click="getExamName">从父组件获取名字</button>
props: ['nameReceived'],
  methods: {
    getExamName() {
      console.log('从父组件收到的名字为', this.nameReceived);
    },
  },

效果展示:

image.png

  1. 子组件向父组件传值: 通过使用props传递函数的方式实现子组件向父组件传值,实现流程如下:
    (1) 在父组件中调用子组件时,在子组件标签中绑定函数,代码如下
 <Exam :getExamName="getExamName" />
 methods: {
 getExamName(examName) {
      console.log('父组件收到的考试名称', examName);
    },
 },

(2) 在子组件props中定义与绑定值相同的变量,用来接收父组件传递过来的函数,将子组件的要传递值作为函数的入参,调用该函数后就将参数传递给父组件,代码如下:

<button @click="sendExamName">向父组件传递名字</button>
 props: ['getExamName'],
 methods: {
   sendExamName() {
     this.getExamName(this.examName);
   },
 },

实现效果图如下:

image.png

二、组件的自定义事件

区别于JS内置事件,供组件使用,用于子组件向父组件传递数据。自定义事件在使用时需要与组件进行绑定,不用的时候进行解绑。实现原理为:父组件为子组件绑定带参数的自定义事件,然后在子组件中进行触发事件,并对事件进行传值。实现步骤如下:

  1. 绑定:

(1)在父组件中使用

<Exam @customEvent="testMethod" />

methods: {
    testMethod(examName) {
      console.log('父组件通过自定义事件收到的考试名称', examName);
    },
  },

(2) 在子组件中触发事件

this.$emit('customEventName', 参数)

父组件另一种绑定形式:

<A ref='refName' />

mounted(){
	this.$refs.refName.$on('customEvent', this.testMethod)
}

使用第二种方式虽然看起来比较复杂,但是灵活性很高,如可以实现延时绑定等操作。 实现效果如下: image.png

解绑:

this.$off('customEventName')

组件也可以绑定原生DOM事件,需要用native修饰符。

注意:

使用第二种方式绑定自定义事件,但是将回调函数直接写在this.$refs.refName('customEventName',回调函数) 中时,必须使用箭头函数,放置this指向错误。

自定义事件与props传递函数的区别: 使用props须在子组件中定义对应的变量,但是使用自定义事件不需要使用props进行接收。

三、全局事件总线

借助一个所有组件都可以访问到的全局公共总线来定义事件,需要接收数据的组件进行监听然后触发自身回调函数来接收数据,可以实现任意组件间的通信。

  1. 定义全局事件总线:
new Vue({
  render: (h) => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this; // 安装全局事件总线
  },
}).$mount('#app');
  1. 使用全局事件总线:

(1)接收数据:A组件想接收数据,需在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。

 methods: {
    testMethod(ExamName) {
      console.log('父组件全局事件总线接收到的数据', ExamName);
    },
 mounted() {
    this.$bus.$on('customBus', this.testMethod);
 },

(2) 提供数据:

    sendExamName() {
      this.$bus.$emit('customBus', this.examName);
    },
  },

实现效果图如下:

image.png Exam组件发送数据,父亲组件和兄弟组件都能收到数据,组件之间的通信不用再纠结父子关系,非常方便。

  1. 最好在beforeDestroy钩子中,使用$off去解除当前组件所用到的事件。
beforeDestroy() {
  this.$bus.$off("customBus");
}

四、消息订阅与发布

消息的订阅与发布实现步骤与全局事件总线很像,都是需要数据的组件进行监听,由发送数据组件进行事件触发或者发布。

  1. 安装pubsub: npm i pubsub-js
  2. 消息发布:
sendExamName() {
      pubsub.publish('test', this.examName);
    },
  1. 消息订阅:
mounted() {
    pubsub.subscribe('test', this.test);
  },
  1. 取消订阅:
  beforeDestroy(){
    pubsub.unsubscribe('订阅实例PID')
  }

实现的效果与全局事件总线的基本一样, 推荐使用全局事件总线。