相比React受控组件的概念,Vue组件之间的“通讯”特征则表现的更强。javascript
这种“通讯”特性表如今,组件内部拥有一套本身的状态管理,对外只表现为信息的传递,而不须要外部组件特地作出什么行为(例如受控组件的状态彻底是由控制者决定,受控组件状态的改变必需要求控制者作出响应的行为)vue
除了常见的父子级别通讯,还有兄弟级、跨级,到总线和Vuex。不得不说Vue组件通讯的方式要更丰富一些。java
props
最基础的父传子手段。vuex
// child指定props
export default {
props: {
msg: String
}
}
// parent传递消息
<child msg='msg' />
复制代码
ref
和children
直接获取子组件引用来设置子组件的内部值。children
是一个数组,装着全部自定义子组件,但多个子组件状况下排列不能保证顺序。因此更可靠的仍是子组件制定ref
,父组件使用$refs
获取子组件引用。数组
// child
export default {
data() {
return {
// parent msg by $refs
// or
// parent msg by $children
current: ''
}
}
}
// parent
<child ref="child">
export default {
methods: {
handleChange1() {
this.$refs.child.current = 'parent msg by $refs'
},
handleChange2() {
this.$children[0].current = 'parent msg by $children'
}
},
mounted() {
// this.handleChange1()
// or
// this.handleChange2()
}
}
复制代码
最核心的向上传递消息的手段markdown
// child
<button @click="sendMsg" />
export default {
methods: {
sendMsg() {
this.$emit('sendMsg', { msg: 'msg' })
}
}
}
// parent
<child @send-msg="receiveMsg" />
export default {
methods: {
receiveMsg(param) {
console.log(param) // { msg: 'msg' }
}
}
}
复制代码
v-model
和.sync
的本质也是props
➕自定义事件的组合数据结构
$attr
传递那些子组件没有设定在props
里面的值,一般在子组件中使用inheritAttrs: false
来取消非props
值在根组件上的继承。不过$attrs
特殊的是,能够在“族谱”中一直向后传递信息:每一个成员使用v-bind="$attrs"
均可以将祖先的非props
属性传递下去。ide
// grandson
export default {
mounted() {
console.log(this.$attrs.attr) // attr
}
}
// child
<grandson v-bing="$attrs" />
export default {
props: {
msg: String
},
mounted() {
console.log(this.msg, this.$attrs.attr) // props, attr
}
}
// parent传递props消息和attrs消息
<child msg="prop" attr="attr" />
复制代码
provide
/inject
一个祖先向全部后代提供消息的手段,没必要由每一代传递消息oop
// grandson
export default {
inject: ['msg'],
mounted() {
console.log(this.msg) // 'msg'
}
}
// child
<grandson />
// parent
<child />
export default {
provide() {
return {
msg: 'msg'
}
}
}
复制代码
$listeners
$listeners
能够一直向后传递事件(普通事件和自定义事件),由某一后代触发事件,实现向祖先传递消息ui
// grandson
<button @click="sendMsg">触发祖先的自定义事件</button>
export default {
methods: {
sendMsg() {
this.$listeners['on-send']({ grandson: 'grandson' })
}
}
}
// child
<grandson v-on="$listeners"/>
// parent
<child @on-send="receiveMsg" />
export default {
methods: {
receiveMsg(param) {
console.log(param) // { grandson: 'grandson' }
}
}
}
复制代码
// brother-send
export default {
mounted() {
this.$parent.$emit('parent-msg', { msg: 'msg by parent' })
this.$root.$emit('root-msg', { msg: 'msg by root' })
}
}
// brother-receive
export default {
created() {
this.$parent.$on('parent-msg', (param) => {
console.log(param) // { msg: 'msg by parent' }
})
this.$root.$on('root-msg', (param) => {
console.log(param) // { msg: 'msg by root' }
})
},
destroyed() {
this.$parent.$off('parent-msg')
this.$root.$off('root-msg')
}
}
// parent
<div>
<brother-send />
<brother-receive />
</div>
复制代码
能够直接借助一个空Vue对象,自带$on
$emit
$off
的API
// bus.js
export default new Vue()
复制代码
也能够本身构造
// bus.js
class Bus {
constructor() {
this.callbacks = {}
}
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name, ...args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach(cb => cb(...args))
}
}
$off(name) {
this.callbacks[name] = null
Reflect.deleteProperty(this.callbacks, name)
}
}
export default new Bus()
复制代码
Vuex
能解决全部组件之间的通讯问题,但实际上Vuex
更像是一个状态管理的“库”。Vuex
相对比较重,可是能保存全部须要的数据结构,而且全部组件均可以访问到。是否使用Vuex
仍是取决于项目规模,或者说是数据规模。