Vue 组件通信的方式

前言

首先要了解的是,组件通信的几种情况:父子组件通信,隔代组件通信(父孙组件通信),兄弟组件通信。

通信方式

props 和 $emit

适用于父子组件通信

props 是从父组件向子组件传递数据,$emit 是从子组件向父组件传递数据,这是 Vue 组件通信的基础。

<!-- Parent.vue -->
<template>
  <div>
    <child :value="text" @input="handleValue"></child>
    <h1>{{text}}</h1>
  </div>
</template>
<script>
import Child from "./Child.vue";
export default {
  data () {
    return {
      text: "父组件!"
    }
  },
  components :{
    Child
  },
  methods: {
    handleValue (value) {
      this.text = value;  // 子组件传递过来的输入框数据
    }
  }
}
</script>

<!-- Child.vue -->
<template>
  <input type="text" @input="handleInput" :value="value">
	<!-- 此时的 value 是是从父组件传递过来的数据,'父组件' -->
</template>
<script>
export default {
  props: ['value'],
  methods: {
    handleInput (e) {
      this.$emit('input', e.target.value);
    }
  }
}
</script>

props 传递数据是单向传递的,只能由父组件向子组件传递,父组件中的数据发生改变,子组件中的数据也会随之改变。

ref 和 $parent / $children

适用于父子组件通信

通过 $ref 组件,父组件可以获取到子组件上所有的实例 data 和 方法,通过 $parent 子组件可以获取到父组件所有的实例 data 和 方法,通过 $children 父组件可以获取到子组件的实例 data 和 方法。

<!-- Parent.vue -->
<template>
  <div>
    <button @click="handleClick">+1</button>
    <p>{{value}}</p>
    <child ref="child"></child>
  </div>
</template>
<script>
import Child from './Child.vue'
export default {
  data () {
    return {
      value: 0
    }
  },
  components: {
    Child
  },
  methods: {
    handleClick () {
      this.$refs.child.changeNumber (this.value += 1)
    },
    changeValue (value) {
      this.value = +value
    }
  }
}
</script>

<!-- Child.vue -->
<template>
  <input type="text" :value="number" @input="handleInput">
</template>
<script>
export default {
  data () {
    return {
      number: 0
    }
  },
  methods: {
    handleInput (e) {
      let number = e.target.value
      this.$parent.changeValue(number?number:0);
    },
    changeNumber (value) {
      this.number = value
    }
  }
}
</script>


EventBus(也叫发布订阅者模式)

适用于父子,隔代,兄弟组件通信

使用 EventBus 之前,需要在全局注册一个 EventBus 方法,这里我们将 EventBus 注册到 Vue 原型上。

//  main.js
import Vue from 'vue'
Vue.prototype.$EventBus = new Vue()

实现一个兄弟组件通信

<!-- Parent.vue -->
<template>
  <div>
    <child1></child1>
    <child2></child2>
  </div>
</template>
<script>
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue"
export default {
  components: {
    Child1,
    Child2
  }
}
</script>

<!-- Child1.vue -->
<template>
  <input type="text" @input="handleInput" placeholder="请输入内容">
</template>
<script>
export default {
  methods: {
    handleInput (e) {
      this.$EventBus.$emit("handleShow", e.target.value);
    }
  }
}
</script>


<!-- Child2.vue -->
<template>
  <p>{{text}}</p>
</template>
<script>
export default {
  data () {
    return {
      text: ""
    }
  },
  mounted () {
    this.$EventBus.$on("handleShow", this.handleContent);
  },
  beforeDestroy() {
    this.$EventBus.$off("handleShow", this.handleContent);
  },
  methods: {
    handleContent (text) {
      this.text = text;
    }
  }
}
</script>

在 Child1 组件中,通过 E v e n t B u s . EventBus. EventBus.emit 发射一个事件,在 Child2 兄弟组件中,通过 E v e n t B u s . EventBus. EventBus.on 接收事件,并且第二个参数传回调函数,拿到传递过来的数据,最后在 beforeDestroy 这个生命周期中,通过 E v e n t B u s . EventBus. EventBus.off销毁事件。

VueX

适用于父子,隔代,兄弟组件通信

使用 VueX 首先需要安装 VueX

npm install vuex

在main.js 引入 vuex

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

vuex 的核心

  • state:用于保存数据
state: {
    count: 0
}
  • getter:用于修饰数据,在这里可以对 state 中的数据进行特殊修改
getters: {
    getCount: state => state.count,
    //  例如
    sum: state => state.count + 10
}
  • mutation:改变 state,通过 commit 提交 mutation 改变 state,mutation是唯一可以改变 store 状态的方式。
mutations: {
    addCount: state => state.count++
}

mutation必须是同步函数

  • action:异步的改变state操作,但是只能通过commit提交mutation来改变state,不能直接修改state,通过dispatch提交action操作。
actions: {
    addCount ({commit}) {
        setTimeout(() => commit('addCount') ,2000);
    }
}

例子:

//  main.js
const store = new Vuex.Store({
  state: {
    count: 0
  },
  getters: {
    getCount: state => state.count,
    sum: state => state.count + 10
  },
  mutations: {
    addCountSync: state => state.count++
  },
  actions: {
    addCount ({commit}) {
      setTimeout(() => commit('addCountSync') ,2000);
    }
  }
});
new Vue({
    ...
    store
})
<template>
  <div>
    <h1>{{count}}</h1>
    <button @click="handleClickSync">同步改变count</button><br>
    <button @click="handleClick">异步改变count</button>
  </div>
</template>
<script>
export default {
  computed: {
    count () {
      return this.$store.getters.getCount
    }
  },
  methods: {
    handleClickSync () {
      this.$store.commit('addCountSync');
    },
    handleClick () {
      this.$store.dispatch('addCount');
    }
  }
}
</script>

provide 和 inject

适用于隔代组件

// parent.vue
export default {
    provide(){
        return {
            parentName: '我是父组件标题'
        }
    }
}

// child1.vue
export default {
    inject: ['parentName']
}

上一篇:Android EventBus 知识


下一篇:Vue造*-Tabs测试(上)