1、使用之前
在講解這個語法糖之前,我們有必要先了解 Vue 中組件之間 單向數據流
通信規則:
Vue 提倡單向數據流,即父級 props 的更新會流向子組件,但是反過來則不行。這是爲了防止意外的改變父組件狀態,使得應用的數據流變得難以理解。如果破壞了單向數據流,當應用複雜時,debug 的成本會非常高。
所以開發中,我們需要遵循:父組件可以修改子組件的內容,而子組件是不能(不推薦)直接改變父組件的內容,但子組件可以通過事件觸發的方式通知父組件來修改自己本身的內容。
2、案例對比
場景:控制彈框的顯示與關閉。在父組件中打開子組件彈框,然後在點擊子組件中的按鈕關閉彈框。
我們父子傳值的做法如下:
// 父組件
<template>
<div>
<button @click="show">打開彈窗</button>
<i-dialog @visibleState="changeVisible" :visible="display" />
</div>
</template>
<script>
import iDialog from "./iDialog.vue";
export default {
name: 'iDialog',
components: {
iDialog,
},
data() {
return {
display: false,
};
},
methods: {
show() {
this.display = true;
},
changeVisible(val) {
this.display = val;
},
}
};
</script>
// 子組件
<template>
<div v-show="visible">
點我關閉子組件
<button @click="doClose">點我隱身</button>
</div>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false,
},
},
methods: {
doClose() {
this.$emit("visibleState", false);
},
},
};
</script>
通過以上,我們就簡單的模擬了一個點擊彈窗和關閉彈窗的功能,這樣的寫法沒問題,但是顯得比較繞,讓人不好去理解這其中的邏輯。
使用 .sync 語法糖
首先它是一個語法糖,使用方式,在調用子組件時,通過 :prop.sync="val"
來監聽 prop
屬性值 val
的變化:
<child :prop.sync="val"></child>
然後會被擴展爲:
<child :prop="val" @update:prop="value => val = value"></child>
當子組件需要更新 prop 的值時,它需要顯式地觸發一個更新事件:
this.$emit('update:prop', newValue)
看了以上是不是很熟悉,子組件中,本質上還是通過觸發事件的方式通知父組件來改變自己的屬性值
,只是現在 Vue 內部將其轉化爲一個語法糖,將 :prop="val" @update:prop="value => val = value"
替換成了 :prop.sync="val"
,這樣看起來就簡潔多了。
那麼我們現在就可以使用 .sync
這個語法糖來實現我們最開始的案例了:
// 父組件
<template>
<div>
<button @click="show">打開彈窗</button>
<i-dialog :visible.sync="display" />
</div>
</template>
<script>
import iDialog from "./iDialog.vue";
export default {
name: 'iDialog',
components: {
iDialog,
},
data() {
return {
display: false,
};
},
methods: {
show() {
this.display = true;
}
}
};
</script>
// 子組件
<template>
<div v-show="visible">
點我關閉子組件
<button @click="doClose">點我隱身</button>
</div>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false,
},
},
methods: {
doClose() {
this.$emit("update:visible",false);
},
},
};
</script>