@TOCjavascript
写在前面: vue已经更新到V2.6.10版本(相信很快就会出3.0版本),相信咱们也遇到了须要组件之间通讯的需求,除了主流的vuex状态管理模式,还有哪些方式解决组件之间的通讯的问题,接下来就由我一一介绍给你们;html
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式()。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。具体介绍请转vuex;vue
// cdn
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
// npm
npm install vuex --save
//yarn
yarn add vuex
复制代码
// /src/store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
复制代码
// /src/store.js
/** * 状态树 */
const state = {
count: 0
}
/** * 和组件计算属性同样, store 的计算属性 * getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算 */
const getters = {
getCount (state) {
return state.count || 0
}
}
/** * Vuex 中的 mutation 很是相似于事件: * 更改 Vuex 的 store 中的状态的惟一方法是提交 mutation。 * 每一个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler) */
const mutations = {
mutaCount (state, payload) {
state.count = state.count + 1
}
}
/** * Action 相似于 mutation,不一样在于: * Action 提交的是 mutation,而不是直接变动状态。 * Action 能够包含任意异步操做。 */
const actions = {
actCount ({commit}, payload) {
commit('mutaCount', payload)
}
}
const store = new Vuex.Store(
{
state,
getters,
mutations,
actions
}
)
export default store
复制代码
// src/main.js
...
import store from './store'
/* eslint-disable no-new */
new Vue({
...
store,
...
})
复制代码
以上已经把vuex注入到vue实例;java
组件中使用git
// src/components/vuexOne.vue
//...
methods: {
// ...mapActions(['actCount']), // 辅助函数方式使用,须要组件import {mapActions} from 'vuex'
addCount () {
// this.actCount()
this.$store.dispatch('actCount')
}
}
//...
复制代码
// src/components/vuexTwo.vue
//...
computed: {
// ...mapGetters(['getCount']), // 辅助函数方式使用,须要组件import {mapGetters} from 'vuex'
// 常规方式使用
getCount () {
return this.$store.getters.getCount
}
}
//...
复制代码
此时: 触发vuexOne.vue的addCount时间,vuexTwo.vue的页面能改更新;这就是vuex的简单使用;如需了解 模块module 及其余 辅助函数 等能够阅读文档vuexgithub
效果以下: vuex
总结: Action和Mutation二者的功能很类似 ,而且不少时候,咱们只须要在组件中经过this.$store.commit('xxx') 或者 mapMutations辅助函数来使用 Mutation 直接更新state的数据,而不须要经过 Action 这一步,但 Action 和 Mutation 有个很是大的区别就是: Mutation 必须是同步函数(由于mutation 中混合异步调用会致使你的程序很难调试,因此在此限制为只能进行同步),而Action 能够包含任意异步操做 。npm
EventBus 的实现原理是经过一个空的vue实例做为事件中心,经过它来触发事件($emit) 和监听事件($on), 巧妙而轻量地实现了任何组件间的通讯; (适合少而小的项目使用,若是有大量通讯,依旧推荐vuex)api
首先在utils建立一个新的vue实例,用做 事件中心数组
// utils/eventbus.js
...
import Vue from 'vue'
export default new Vue({
name: 'EventBus'
})
复制代码
<template>
<div class="eventBusOne">
<div class="add-count-button-box">
<div>我是eventBusOne组件:</div>
<div class="add-count-button" @click="addCount">state++</div>
</div>
</div>
</template>
<script>
import eventBus from '../../../utils/eventBus'
export default {
name: 'EventBusOne',
data () {
return {
count: 1
}
},
methods: {
addCount () {
this.count += 1
eventBus.$emit('data-count', this.count)
}
}
}
</script>
复制代码
<template>
<div class="eventBusTwo">
<div class="add-count-button-box">
<div>我是eventBusTwo组件:</div>
<div>{{count}}</div>
</div>
</div>
</template>
<script>
import eventBus from '../../../utils/eventBus'
export default {
name: 'EventBusTwo',
data () {
return {
count: 1
}
},
computed: {
},
mounted () {
eventBus.$on('data-count', data => {
this.count = data
})
}
}
</script>
复制代码
总结: eventBus 原理 是利用一个空的vue实例当作一个事件中心,经过其分发及监听事件来传递数据,也能够实现任何组件间的通讯,包括父子、兄弟、跨级等。但当使用过多容易形成命名冲突,所以不利于大项目使用(当大项目使用时,依旧推荐vuex)
ps:以上是目前使用比较多的能够跨组件包括兄弟组件通讯的方法,接下来说其余有短板的方法,有兴趣的能够花几分钟继续往下了解,不然客官能够止步于此,以避免浪费您宝贵的时间 ...
props 由父组件A往子组件B传递数据,固然还能够继续组件B仍然能够往C组件(A的孙组件)继续往下传递,
<template>
<div class="propsOne">
<div class="add-count-button-box">
<div>我是propsOne组件:</div>
<div class="add-count-button" @click="addCount">count++</div>
<div class="add-count-button" @click="addState">state++</div>
</div>
<propsTwo v-model="count" :state="state" @addCount="twoAddCount" @addState="twoAddState"></propsTwo>
</div>
</template>
<script>
import propsTwo from './propsTwo'
export default {
name: 'PropsOne',
components: {
propsTwo
},
data () {
return {
count: 1,
state: 1
}
},
methods: {
addCount () {
this.count += 1
},
addState () {
this.state += 1
},
twoAddCount (value) {
this.count = value
},
twoAddState (value) {
this.state = value
}
}
}
</script>
复制代码
<template>
<div class="propsTwo">
<div>count:{{value}}</div>
<div class="state">state:{{state}}</div>
<div>我是 propsTwo组件: </div>
<div class="add-count-button" @click="addCount">count++</div>
<div class="add-count-button" @click="addState">state++</div>
</div>
</template>
<script>
export default {
name: 'PropsTwo',
props: {
value: {
type: Number,
default: 1
},
state: {
type: Number,
default: 1
}
},
data () {
return {
}
},
methods: {
addCount () {
let count = this.value
count++
this.$emit('addCount', count)
},
addState () {
let state = this.state
state++
this.$emit('addState', state)
}
}
}
</script>
复制代码
总结: props是单向数据流,即只能从父级传到子级,子级改变,父级的值不会改变(用.sync修饰符修饰能够实现双向数据绑定),但v-model是双向数据流,即双向绑定,子级改变这个值时,父级也会跟着改变;$emit传值和上面第二种的eventbus的原理一致,不过是事件分发到父级,父级能够监听;想了解sync修饰符请转vue.org
ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子组件上,引用就指向组件
实例:
// ref.vue
<template>
<div class="ref">
<div class="add-count-button" @click="getCount">
获取refTwo的count,其值为:{{count}}
</div>
<refOne ref="refOne"></refOne>
</div>
</template>
<script>
import refOne from '../components/refDemo/refOne'
export default {
name: 'Props',
components: {
refOne
},
data () {
return {
count: ''
}
},
methods: {
getCount () {
console.log('ref========', this.$parent) // Vue
console.log('ref========', this.$children) // refOne
this.count = this.$refs.refOne.getCount()
}
}
}
</script>
复制代码
// refOne
<template>
<div class="refOne">
<refTwo ref="refTwo"></refTwo>
<refTwo></refTwo>
</div>
</template>
<script>
import refTwo from './refTwo'
export default {
name: 'RefOne',
components: {
refTwo
},
data () {
return {
count: 2
}
},
methods: {
getCount () {
console.log('refOne========', this.$parent) // refOne
console.log('refOne========', this.$children) // [refTwo,refTwo]
return this.$refs.refTwo.getCount()
}
}
}
</script>
复制代码
// refTwo
<template>
<div class="refTwo">
<div class="add-count-button-box">
<div>我是refTwo组件的count ==== {{count}}</div>
</div>
</div>
</template>
<script>
export default {
name: 'RefTwo',
data () {
return {
count: 1000
}
},
methods: {
getCount () {
console.log('refTwo========', this.$parent) // refOne
console.log('refTwo========', this.$children) // []
return this.count
}
}
}
</script>
复制代码
从上面的操做可知,经过ref调用子组件的方法,能够把相应的数据传导到父级;
特别地 $children拿到的当前实例的直接子组件。须要注意 $children 并不保证顺序,也不是响应式的。若是你发现本身正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,而且使用 Array 做为真正的来源。
$parent、$children 从上述的打印,依旧能够发现$parent、$children能拿到当前组件的父级或者子级组件实例,若是有多个,则为数组,若是为空,则为空数组,若是经过这个实例去拿相应的属性或者方法也是可行的 以下:
// ref
methods: {
getCount () {
console.log('ref========', this.$parent) // Vue
console.log('ref========', this.$children) // refOne
this.count = this.$refs.refOne.count // count 为 refOne的data里面的count ===2
}
}
复制代码
ref请转vue.org $parent请转vue.org $children请转vue.org
如: provide与inject
provide 和 inject (Vue2.2.0新增API) 绑定 并非可响应的。这是刻意为之的。然而,若是你传入了一个可监听的对象,那么其对象的属性仍是可响应的。 provide与inject 转vue.org
如: $attrs/ $listeners
$attrs/ $listeners(Vue2.4增长) 版本在普通组件中,没有被定义为 prop 的特性会自动添加到组件的根元素上,将已有的同名特性进行替换或与其进行智能合并。 $attrs/ $listeners转vue.org
万能通讯: vuex、eventBus 父子通讯:$refs 、 $parent、$children、provide/inject;