前言
有時候我們需要對一個組件綁定自定義 v-model,以更方便地實現雙向數據,例如自定義表單輸入控件。
甚至有時候,我們想要實現綁定多個 “v-model”,也就是多個“雙向綁定”,例如帶表單輸入的模塊框,想同時控制模態框的顯示狀態與表單的輸入狀態。好在 vue 3 已經實現了多 v-model,那么在 vue 2 上我們可以如下實現。
1.單個“雙向綁定”的實現
使用 model 實現
其實 v-model 只是 value + change 的語法糖,監聽輸入並觸發改變,因此只要實現 “監聽” + “觸發” 就可以自定義 v-model 啦。
<!-- 父組件 --> <template> <Child v-model="value" /> </template> <script> export default { data() { return { value: '' } } } </script> <!-- 子組件 --> <template> <input v-model="input" /> </template> <script> export default { props: { value: String, }, model: { prop: 'value', // 指定 v-model 要綁定的參數叫什么名字,來自於 props 中定義的參數 event: 'change', // 指定要觸發的事件名字,將被用於 $emit }, computed: { input: { // 這里的計算屬性使用了 getter、setter,可以簡化代碼 // 可參見鏈接 https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter get() { return this.value; }, set(val) { this.$emit('change', val); // 觸發 } } } } </script>
這樣一來,就實現了自定義組件的 v-model 實現,重點在於子組件中 model 的聲明和 emit 事件。
2.使用 .sync 實現
除了上面 model 的方法,其實還可以通過 sync 來實現。同樣也是處理“監聽”和“觸發”就行。
在官方文檔中有寫,https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修飾符
用上面相似的例子,可以這樣來實現:
<!-- 父組件 --> <template> <Child :value.sync="value" /> </template> <script> export default { data() { return { value: '' } } } </script> <!-- 子組件 Child --> <template> <input v-model="input" /> </template> <script> export default { props: { value: String, }, computed: { input: { get() { return this.value; }, set(val) { this.$emit('update:value', val); // 這里的事件名字一定是 'update:' + prop的名字 } } } } </script>
很顯然,使用這種方法的代碼量比第1種要少,因為不用寫 model 屬性。只是比起 v-model,v-bind:value.sync 的寫法還是不那么“引人注目”
多個“雙向綁定”的實現
在 vue 3 出來之前,我們知道在一個標簽里面最多只能有一個 v-model。但這並不意味着一個組件只能一次雙向數據綁定。
根據上面 .sync 的方法,我們可以舉一反三,多幾個 update:xxxx 就可以了。
1.分開綁定
下面以一個帶輸入框的模態框為例子,需求是父組件能夠打開模態框,子組件在輸入確認后能夠關閉模態框;子組件能夠輸入,確認后能夠將值傳給父組件。
<!-- 父組件 --> <template> <!-- 定義了兩個v-bind:xxx.sync來實現兩個雙向綁定 --> <ModalInput :value.sync="value" :show.sync="show" /> </template> <script> export default { data() { return { value: '', show: false } } } </script> <!-- 子組件 ModalInput --> <template> <!-- 這里假設Modal是一個帶“確認”按鈕,點擊觸發confirm事件,並利用v-model來控制展示的模態框 --> <Modal v-model="showModal" @confirm="onConfirm"> <input v-model="input"> </Modal> </template> <script> export default { props: { value: String, show: Boolean, }, data() { return { input: '' // 在這個例子中,使用 data 來聲明 input, // 因為只有在點擊了“確認”按鈕后,才要把值傳給父組件(而不是實時傳) } }, computed: { showModal: { get() { return this.show; }, set(val) { this.$emit('update:show', val); } } }, methods: { onConfirm() { this.$emit('update:value', this.input); this.showModal = false } } } </script>
2.合並綁定
上面是綁定了兩個獨立變量的雙向綁定,按照官方的文檔,我們甚至還可以用 v-bind.sync 來綁定整個對象(的所有成員!)。下面假設一個表單組件,同時收集個人多個信息
<!-- 父組件 --> <template> <UserInfoForm v-bind.sync="inputs" /> </template> <script> export default { data() { return { inputs: { name: '', age: 0, addr: '', phone: '' } } } } </script> <!-- 子組件 UserInfoForm --> <template> <form> <input v-model="name"> <input v-model.number="age"> <input v-model="addr"> <input v-model="phone"> </form> </template> <script> // 與上面例子實現方式相似,這里省略代碼若干行。。。 // 其實就是聲明入參 props 有哪些 // 用 computed 來聲明各個變量的 getter 和 setter // getter 返回傳進來的 prop,setter 中觸發 update:xxxx 事件 </script>
————————————————
版權聲明:本文為CSDN博主「Dobility」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Dobility/article/details/110147985