Vue(五)组件通信方式总结

310 阅读2分钟

父子组件通信

(1)props 父 -> 子

子组件通过 props 属性来接收父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。

  • 父组件:使用子组件并添加属性,将 data 里的属性值绑定传入
  • 子组件:通过 props 接收,在 methods 或生命周期里以this.XXX的方式使用
//  父组件
<template>
  <son :name="username" />
</template>
<script>
import son from './son.vue';
export default {
  components: { son },
  data() {
    return {
      username: 'lucy'
    }
  }  
}
</script>
//  子组件
props: {
  name: {
    type: String,
    default: ''
  }
},
methods:{
  f1(){
    this.name='jack';
  },
}

(2)this.$emit 子 -> 父

  • 子组件:在methods的函数里 this.$emit(事件名,传参)向外弹出一个自定义事件
  • 父组件:使用子组件时监听该事件,获取参数:@事件名=传参
//子组件
<button @click="updateUser">点我</button>
...
props: ['user'],
events: ['update:user'],
methods: {
  updateUser(){
    this.$emit('update:user',this.user+'!')
  }
}
//父组件
<son v-bind:user="username" @update:user="username=$event" />

上述写法等价于

<son v-model:user="username" />

注意:emit原则上可以弹出任何自定义事件,但使用v-model简写时,emit触发的必须是update:props属性这类事件。

(3)$attrs 父 -> 子(非 props 属性)

$attrs 可以获取父组件传进来,没有通过props接收的属性

// 父组件
<Child :title="title" :desc="desc" >/>

//  子组件内
<template>
<div>
  <h2>{{title}}</h2>
  <p>{{$attrs.desc}}</p>
</div>
</template>	
<script>
export default {
  props: ['title']
  // ...
}
<script>

(4)插槽 子->父传值

希望在父组件内能够使用子组件内的变量 item ,将变量绑定到插槽上。

// 子组件
<ul>
  <li v-for="(item,index) in news">
    <slot :item="item" :index="index"></slot>
  </li>
</ul>
...
data() {
  return {
    news: ['first news', 'second news']
  }
}

父组件v-slot获取子组件插槽传过来的参数

// 父组件
<son v-slot="props">第{{props.index}}章{{props.item}}</slot>

爷孙 依赖/注入(provide/inject)

适用于深层嵌套的组件,一个顶层父组件可以为所有后代组件直接提供数据。 image.png 在父组件中通过 provide 提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide 中的数据。

//  顶层父组件
export default {
  // ...
  provide(){
    return {
      message: 'hello world!'
    }
  }
}

//  后代组件
export default {
  // ...
  inject: ['message'],
}

任意两个组件通信

(1)事件总线 EventBus

创建一个事件中心来管理组件之间的通信。

// event-bus.js 
import Vue from 'vue';
export const eventbus = new Vue();

任意组件一:

//  触发事件
import { eventbus } from './event-bus.js'; // 引入事件中心
export default {
  // methods 里
  eventbus.$emit('termWord', itemData.orgChunk);
}

任意组件二:

import { eventbus } from './event-bus.js'; 
export default {
  data() {
    return {
      termWord: '',
      val: '',
    }
  }
  // mounted 里监听事件
  eventbus.$on('termWord', (val) => {
    this.termWord = val;
  });
  // beforeDestroy 取消监听
  eventbus.$off('termWord');
}
  • 问题:如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,项目维护困难。
  • 解决:使用 Vuex。将这些公共的数据抽离出来,作为一个全局的变量来管理,然后其他组件就可以对这个公共数据进行读写操作。

(2)Vuex 状态管理

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库,用于任意组件的任意通讯。

  • store 创建的全局唯一的状态管理仓库,包含以下所有内容:
  • State 用来读取状态,带有一个 mapState 辅助函数
  • Getter 用来读取派生状态,附有一个 mapGetters 辅助函数
  • Mutation 用于同步提交状态变更,附有一个 mapMutations 辅助函数(同步写)
  • Action 用于异步变更状态,但它提交的是 mutation,而不是直接变更状态(一步写)
  • Module 用来给 store 划分模块,方便维护代码。
//src/store/mutation-types.js
export const SET_GUIDE_SHOW = 'SET_GUIDE_SHOW';
// global.js
import * as types from '../mutation-types';
// 初始state状态
const stateGlobal = {
  guideShow: 0,
}
// 可以做filter数据处理,也可以原始输出
const getters = {
  getGuideShow: (state) => state.guideShow,
}
// 可以异步获取数据,也可以在组件中使用dispatch来发出actions
const actions = {
  [types.SET_GUIDE_SHOW]({ commit }, guideShow) {
    commit(types.SET_GUIDE_SHOW, guideShow);
  },
}
// 更新state状态
const mutations = {
  [types.SET_GUIDE_SHOW](state, guideShow) {
    state.guideShow = guideShow;
  },
}

使用

import { mapGetters } from 'vuex';
import { SET_GUIDE_SHOW } from '@/store/mutation-types';
export default {
  ...mapGetters([
    'getGuideShow',
  ]),
  // this.getGuideShow

详细可访问下方Vuex文档学习 vuex.vuejs.org/zh/