vue通信方式有很多,項目中用的比較多的的有pros、vuex、$emit/$on
這3種,還有provide/inject
(適合高階組件)、$attrs和$listeners
(適合高階組件)以及$parent/$child/ref、eventBus
等這3種方式。
1、pros
父子組件通信
vue使用props有兩種形式形式實現父子組件之間的數據傳遞。官方描述:props
// 第一種方式
// parent.vue
<template>
<div>
<child :message="childName" @change= "changeMessage" />
</div>
</template>
<script>
import childfrom './child';
export default {
components: {
child,
},
data() {
return {
message: '我是父組件傳遞的數據',
};
},
methods: {
changeMessage(val) {
this.message= val;
},
},
};
</script>
// child
<template>
<div>{{message}}</div>
<button @click="changeMessage">change</button>
</template>
<script>
export default {
props: ['message'],
methods: {
changeMessage() {
this.$emit('change', '我是傳遞給父組件的數據')
}
}
};
</script>
父組件通過:message向子組件傳遞數據,子組件通過$emit觸發數據變化,父組件使用$on來監聽子組件數據的變化。
// 第二種方式
// parent.vue
<template>
<div>
<child v-modle="message" />
</div>
</template>
<script>
import child from './child';
export default {
components: {
child,
},
data() {
return {
message: '我是父組件傳遞的數據',
};
}
};
</script>
// child
<template>
<input v-model="sync_value" />
</template>
<script>
import propsync from '@/mixins/propsync'
export default {
mixins: [propsync],
props: {
value: {
default: '',
isSync: true
}
}
};
</script>
第二種方式是自動化的props雙向數據綁定,直接引入mixin,並在配置中聲明mixin即可: mixins: [propsync],
propsync默認會將所有props創建雙向綁定,可通過isSync:false
來聲明此props不需要創建雙向綁定。
2、provide/inject
一般適用於高階組件,祖父組件想多級子組件傳遞數據,官方描述:provide / inject。以允許一個祖先組件向其所有子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。
provide 選項是:一個對象或返回一個對象的函數
inject 選項是:一個字符串數組,或 一個對象,對象的 key 是本地的綁定名
// parent.vue
<script>
export default {
provide() {
message: '我是爺爺'
},
};
</script>
// child
<script>
export default {
inject: ['message'],
created () {
console.log(this.message) // => "我是爺爺"
}
};
</script>
3、$attrs和$listeners
$attr: 向 子組件 傳遞,當前組件 沒有接收的,父組件傳遞下來的 prop 。
$listeners: 向父組件傳遞,當前組件沒有接收的,子組件拋出的自定義事件。
// parent.vue
<template>
<input type="text" v-bind="$attrs" v-on="$listeners">
</template>
// child.vue
<template>
<input type="text" v-bind="$attrs" @input="observerInput">
</template>
<script>
export default {
methods: {
// 攔截內置事件
observerInput (el) {
this.$emit('input', el.target.value)
},
},
}
</script>
4、eventBus
跨組件通信
class EventBus{
constructor(){
this.event=Object.create(null);
};
//註冊事件
on(name,fn){
if(!this.event[name]){
//一個事件可能有多個監聽者
this.event[name]=[];
};
this.event[name].push(fn);
};
//觸發事件
emit(name,...args){
//給回調函數傳參
this.event[name]&&this.event[name].forEach(fn => {
fn(...args)
});
};
//只被觸發一次的事件
once(name,fn){
//在這裏同時完成了對該事件的註冊、對該事件的觸發,並在最後取消該事件。
const cb=(...args)=>{
//觸發
fn(...args);
//取消
this.off(name,fn);
};
//監聽
this.on(name,cb);
};
//取消事件
off(name,offcb){
if(this.event[name]){
let index=this.event[name].findIndex((fn)=>{
return offcb===fn;
})
this.event[name].splice(index,1);
if(!this.event[name].length){
delete this.event[name];
}
}
}
}
聲明一個全局Vue實例變量 EventBus
, 把所有的通信數據,事件監聽都存儲到這個變量上。這樣就達到在組件間數據共享了,有點類似於 vuex。但這種方式只適用於極小的項目,複雜項目還是推薦 vuex。