相比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
仍是取決於項目規模,或者說是數據規模。