最近的项目中又重新用起了vue,在此项目中遇到了组件间通信难的问题。这篇文章主要根据自己查到的资料及实操介绍下vue组件间通信的解决方法

父子组件之间的传值

父组件向子组件传值

父组件传值给子组件用 ":子组件接收的参数名=要传的值"。如图:

子组件用props接收来自父组件的参数。如图:

PS:如果父组件向子组件传的是一个json对象,当子组件改变这个对象的值时,父组件是能直接监听到变化的

关于props的几种写法:
第一种方法

props:['setImKey','setImObj']

第二种方法(限制了参数类型,如果类型不一致会警告)

props:{
  'setImKey': String,
  'setImObj': Object 
}

第三种方法(限制了参数类型,以及给定默认值)

props:{
  'setImKey': {
    'type': String,
    'default': 'SETIM'
  },
  'setImObj': {
    'type': Object 
    'default': {}
  }
}

子组件向父组件传值

先在父组件中给子组件传入事件。"@子组件自定义的方法名=触发的父组件方法"

子组件中用"this.$emit(子组件自定义的方法名, 要传的值)"传值给父组件

子组件直接使用父组件属性或方法

this.$parent.父组件中某方法名() 或 this.$parent.父组件中某属性

父组件直接调用子组件方法或修改子组件的值

给子组件加上索引,用this.$refs.索引名 调用该组件内的方法或修改值。

eventBus通信(适用于中小型项目)

如果有个变量所有地方都会用到,并且组件的嵌套又比较多,再用上述方法就比较繁琐了。这时我们就可以用eventBus来对这种全局变量进行管理

1、新建一个eventBus.js,里面只有两行代码

import Vue from 'vue'
export default new Vue()

2、组件里引入eventBus.js,并在created()钩子中调用$on监听事件获取参数

import Bus from '../eventBus.js'
created: {
    Bus.$on('getTarget', function(val) {
        console.log(val);
  })
}

3、组件里引入eventBus.js,调用$emit设置参数

import Bus from '../eventBus.js'
Bus.$emit('getTarget', 'TargetVal');

vuex

由于多个状态分散的跨越在许多组件和交互间各个角落,大型应用复杂度也经常逐渐增长。为了解决这个问题,Vue 提供了 vuex。
状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。

引入Vuex(前提是已经用Vue脚手架工具构建好项目)

1.利用npm包管理工具,进行安装 vuex。

npm install vuex --save
要注意的是这里一定要加上 --save,因为这个包我们在生产环境中是要使用的。

2、为了便于管理,新建一个config文件夹(这个不是必须的),并在文件夹下新建store.js文件,文件中引入我们的vue和vuex,引入之后用Vue.use进行引用。

import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)

3、在main.js 中引入新建的vuex文件

import store from './config/store.js'

4、再然后 , 在实例化 Vue对象时加入 store 对象 :

new Vue({
  el: '#app',
  router,
  store, // 使用store
  components: { App },
  template: ''
})

定义变量

在store.js文件中用export default 封装代码,让外部可以引用。

export default new Vuex.Store({
  state: {
    // 存储状态。也就是变量;
    name: '张三',
    age: 10,
    obj: {}
  },
  getters: {
    // 派生状态。
    info (stateObj) { // 这里的stateObj对应上面的state
      return '我的名字是:${stateObj.name}。今年${stateObj.age}岁。';
    }
  },
  mutations: {
    // 提交状态修改,为同步修改。(我们不能直接修改state里的变量,如果想修改变量必须用$store.commit(mutations定义的对应方法名, 要修改的值)。)
    setAge (stateObj, age) { // 这里的stateObj对应上面的state
      stateObj.age = age
    }
  },
  actions: {
    // 和mutations类似,为异步修改。用$store.dispatch()来触发actions里的方法
    setAgeAction (context, age) { // 这里的context对应整个$store对象
      context.commit('SET_AGE', age);
      // 你还可以在这里触发其他的mutations方法
    }
  }
})

使用

模板中使用

<span class="name">{{ $store.state.name }}</span>
<p>{{ $store.getters.info }}</p>
PS:如果在js中获取对应的值记得在$store前面加上this.

修改变量

this.$store.commit('setAge', 10); // 同步修改
this.$store.dispatch('setAgeAction', 10); // 异步修改
PS:vuex不能直接修改state里的变量,如果想修改变量必须用commit提交到mutations定义好的方法中去修改。

监听变化

通过computed赋值给某个变量,监听该变量的变化从而达到监听state的效果

computed: {
  myAge () {
    return this.$store.state.age;
  }
},
watch: {
  myAge () {
    console.log('年龄发生了改变')
  }
}

用mapState、mapGetters、mapMutations、mapActions简化模板写法

很多时候 $store.state.dialog.show 、$store.dispatch('switch_dialog') 这种写法又长又臭 , 很不方便。 我们希望像没使用 vuex 那样 , 获取一个状态只需要 this.show , 执行一个方法只需要 this.switch_dialog 就行了 。这时我们就可以用mapXXX来简化模板的写法 ?

首先在组件中用import引入我们的mapXXX

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'

在computed中使用mapState、mapGetters,在methods中使用mapMutations、mapActions

computed: {
  // 这里的三点叫做 扩展运算符 (ES6中的写法)
  ...mapState(['name', 'age']),
  ...mapGetters(['info'])
  }
},
methods: {
  ...mapMutations(['setAge']),
  ...mapActions(['setAgeAction'])
  }
}

现在可以在组件中像原来那样使用这些变量、方法了

<span @click="setAge(20)">{{ name }}</span>