vue2.0中的元件通訊
vue中元件是模組化開發的基礎,在元件A中使用了元件B,那他們必然需要資料通訊,父元件要將資料傳遞給自組建,子元件要通知父元件自己內部發生的事情。
在vue.js中父子元件的關係可以總結為props down, events up,父元件通過props向下傳遞資料給子元件,子元件通過events給父元件反饋訊息,引用官方的一張圖,來看看他們是怎麼工作的
1、父子元件通訊
①父元件向子元件傳遞資料,子元件需要顯式的用props選項宣告它期待接受的資料
父元件傳遞資料:
<parent>
<child :msg="msg"></child>
</parent>
export default {
data() {
return {
msg: [1, 2, 3]
}
}
}
子元件接收資料:
export default {
props: {
msg: {
type: Array,
default() {
return [] // 這裡可以寫預設值
}
}
}
}
初學者常犯的錯誤是使用字面量語法傳遞數值
<child some-props ="1"></child>
它是一個字面prop,傳遞的是字串1,而不是number,如果想傳遞number型別的數值,需要使用v-bind。把它的值當作JaveScript表示式計算:
<child v-bind:some-props="1"></child>
在vue中,子元件是不允許直接修改父元件通過props傳遞過來的資料,這樣會導致父元件和子元件耦合,並且父元件的資料可能會被任意子元件修改,另外每次父元件更新,子元件相應的props都會更新為最新值。之所以想修改props中的資料是因為:
1、我們希望把props中的資料當作區域性資料使用
2、希望把props中的資料處理成其他資料使用
對於這兩種方式我們應該正確的處理為:
定義一個區域性變數,並用props的值初始化它
props: {
someProp: {
type: String,
default: ""
}
},
data () {
return {
initData: this.someProp
}
}
定義一個computed,處理props的值並返回
props: {
someProp: {
type: String,
default: ""
}
},
computed: {
normalData() {
return this.someProp.trim().toLowerCase()
}
}
需要注意的是:JavaScript中陣列和物件是引用型別,指向同一記憶體空間,如果props是陣列或物件,在子元件內部直接改變它會影響父元件的狀態。
②子元件與父元件通訊
我們知道,父元件是使用 props 傳遞資料給子元件,但如果子元件要把資料傳遞回去,應該怎樣做?那就是自定義事件!
父元件可以直接在子元件使用的地方使用v-on繫結事件
父元件繫結事件和傳遞資料:
<parent>
<child @upup="change" :msg="msg"></child> //監聽子元件觸發的upup事件,然後呼叫change方法
</parent>
export default {
data() {
return {
msg: '123'
}
},
methods: {
change(msg) {
this.msg = msg; // 接收子元件傳遞過來的引數,並更新msg,從而子元件也相應的更新msg
}
}
}
子元件接收資料和觸發事件:
<template>
<div @click="up">{{msg}}</div>
</template>
export default {
props: {
msg: {
type: String,
default: ''
}
},
methods: {
up() {
this.$emit('upup','updateMsg'); //主動觸發upup方法,'updateMsg'為向父元件傳遞的資料
}
}
}
③ 父元件如何觸發子元件的事件
<parent @click="doSomeThing">
<child ref="childComp"></child>
</parent>
export default {
methods: {
doSomeThing() {
this.$refs.childComp.yesSir('123')
}
}
}
<template></template>
export default{
methods: {
yesSir(a) {
console.log(a) // 123
}
}
}
2、非父子元件通訊
在簡單的場景下,vue建議我們使用一個空的 Vue 例項作為中央事件匯流排:
新建一個bus.js用於儲存我們空的事件中轉站:
import Vue from 'vue'
export var bus = new Vue()
元件a通過$on繫結事件:
<template>
</template>
import { bus } from 'bus.js'
export default {
created() {
bus.$on('change', () => { //接收事件
this.msg = 'hehe';
});
}
}
元件b通過$emit繫結事件:
<div @click="eve"></div>
import { bus } from 'bus.js'
export default {
methods: {
eve() {
bus.$emit('change','hehe'); //觸發事件
}
}
}