你將:
v-model
是什麼的語法糖? vue2
對原生元件究竟做了什麼特殊處理?v-model
到底是單向資料流還是資料雙向繫結?v-model
在語法糖之外的『副作用』?v-model
語法。v-model
的本質是語法糖。『
v-model
本質上不過是語法糖。它負責監聽使用者的輸入事件以更新資料,並對一些極端場景進行一些特殊處理。』 -- 官方檔案。【相關推薦:】
什麼是語法糖?
語法糖,簡單來說就是『便捷寫法』。
在大部分情況下, v-model="foo"
等價於 :value="foo"
加上 @input="foo = $event"
;
<!-- 在大部分情況下,以下兩種寫法是等價的 --> <el-input v-model="foo" /> <el-input :value="foo" @input="foo = $event" />
沒錯,在大部分情況下如此。
但也有例外:
vue2
給元件提供了 model
屬性,可以讓使用者自定義傳值的prop名和更新值的事件名。這個暫且略過,第四節會細說。
對於原生 html
原生元素,vue
幹了大量『髒活兒』,目的是為了能讓我們忽視 html
在api上的差異性。以下元素的左右兩種寫法是等價的:
textarea
元素:select
下拉框:input type='radio'
單選框:input type='checkbox'
多選框:在程式設計思想上,這種幫助使用者『隱藏細節』的方式叫封裝。
v-model
不僅僅是語法糖,它還有副作用。
副作用如下:如果 v-model
繫結的是響應式物件上某個不存在的屬性,那麼 vue
會悄悄地增加這個屬性,並讓它響應式。
舉個例子,看下面的程式碼:
// template中: <el-input v-model="user.tel"></el-input> // script中: export default { data() { return { user: { name: '公眾號: 前端要摸魚', } } } }
響應式資料中沒有定義 user.tel
屬性,但是 template
裡卻用 v-model
繫結了 user.tel
,猜一猜當你輸入時會發生什麼?
看效果:
揭曉答案吧:user
上會新增 tel
屬性,並且 tel
這個屬性還是響應式的。
這就是『副作用』帶來的效果,你學會了嗎?
v-model
是雙向繫結還是單向資料流?v-model
是雙向繫結嗎?是,官方說是。
『你可以用 v-model 指令在表單 <input>
、<textarea>
及 <select>
元素上建立雙向資料繫結。』 —— vue2官方檔案
v-model
是單向資料流嗎?是的,它甚至是單向資料流的典型正規化。
雖然官方沒有明確表示這點,但我們可以捋一捋兩者的關係。
子元件不能改變父元件傳遞給它的 prop
屬性,推薦的做法是它丟擲事件,通知父元件自行改變繫結的值。
v-model
的做法是怎樣的?v-model
做法完全符合單項資料流。甚至於,它給出了一種在命名和事件定義上的規範。
眾所周知 .sync
修飾符是單向資料流的另一個典型正規化。
『單向資料流』總結起來其實也就8個字:『資料向下,事件向上』。
v-model
雖然不想說,但這確實是高頻面試題。
在定義 vue
元件時,你可以提供一個 model
屬性,用來定義該元件以何種方式支援 v-model
。
model
屬性本身是有預設值的,如下:
// 預設的 model 屬性 export default { model: { prop: 'value', event: 'input' } }
也就是說,如果你不定義 model
屬性,或者你按照當面方法定義屬性,當其他人使用你的自定義元件時,v-model="foo"
就完全等價於 :value="foo"
加上 @input="foo = $event"
。
如果把 model
屬性進行一些改裝,如下:
// 預設的 model 屬性 export default { model: { prop: 'ame', event: 'zard' } }
那麼,v-model="foo"
就等價於 :ame="foo"
加上 @zard="foo = $event"
。
沒錯,就是這麼容易,讓我們看個例子。
先定義一個自定義元件:
<template> <div> 我們是TI{{ ame }}冠軍 <el-button @click="playDota2(1)">加</el-button> <el-button @click="playDota2(-1)">減</el-button> </div> </template> <script> export default { props: { ame: { type: Number, default: 8 } }, model: { // 自定義v-model的格式 prop: 'ame', // 代表 v-model 繫結的prop名 event: 'zard' // 程式碼 v-model 通知父元件更新屬性的事件名 }, methods: { playDota2(step) { const newYear = this.ame + step this.$emit('zard', newYear) } } } </script>
然後我們在父元件中使用該元件:
// template中 <dota v-model="ti"></dota> // script中 export default { data() { return { ti: 8 } } }
看看效果:
讓你的元件支援 v-model
就這麼容易。
獲取原始碼請存取github
https://github.com/zhangshichun/blog-vue2-demos/tree/master/src/views/about-v-model
更多程式設計相關知識,請存取:!!
以上就是帶你深入瞭解vue2中的 v-model,看看如何讓元件支援該語法的詳細內容,更多請關注TW511.COM其它相關文章!