最近 Ant Design Vue 做者 - 唐金州,在某平臺開課了,在整個課程中系統的講述了Vue的開發實戰。在第八講中介紹了Vue雙向綁定的問題,這裏我整理一些資料客觀的分析一下 Vue數據響應原理究竟是不是雙向綁定。javascript
不少同窗在理解 Vue 的時候都把 Vue 的數據響應原理理解爲雙向綁定,但實際上這是不許確的,咱們以前提到的數據響應,都是經過數據的改變去驅動 DOM 視圖的變化,而雙向綁定除了數據驅動 DOM 外, DOM 的變化反過來影響數據,是一個雙向關係,在 Vue 中,咱們能夠經過 v-model
來實現雙向綁定。html
在Vue中體現出雙向綁定做用的方式有兩種,在分析以前咱們先介紹這兩種使用方式有什麼區別。vue
1)v-model 屬性java
2).sync 修飾符git
2.2.0+ 新增github
一個組件上的 v-model
默認會利用名爲 value
的 prop 和名爲 input
的事件,可是像單選框、複選框等類型的輸入控件可能會將 value
特性用於不一樣的目的。model
選項能夠用來避免這樣的衝突:express
ChildBox.vueapp
<template>
<input type="checkbox"
:checked="checked"
@change="$emit('change', $event.target.checked)"/>
</template>
<script>
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
}
}
</script>
複製代碼
Index.vuedom
<template>
<div> <ChildBox v-model="val"/> <!-- 解析後 --> <ChildBox :value="val" @change="data => (val = data)"/> </div> </template> 複製代碼
分析一下上面的代碼。ChildBox.vue文件對checkbox作了簡單的封裝,提供了checked參數。Index.vue文件爲父組件,引用了ChildBox做爲本身的子組件,這裏須要注意一下。val值的綁定使用的v-model而並非v-bind:checkbox。一開始咱們有說到雙向綁定方式有兩種一種是v-model,另外一種是.sync(這個後面講)。若是使用v-model,子組件的props應該設置value值,而向上傳遞應該爲$emit('input')纔對。因此這裏還有一個重點,model
的做用。函數
2.2.0 新增
容許一個自定義組件在使用 v-model
時定製 prop 和 event。默認狀況下,一個組件上的 v-model
會把 value
用做 prop 且把 input
用做 event,可是一些輸入類型好比單選框和複選框按鈕可能想使用 value
prop 來達到不一樣的目的。使用 model
選項能夠迴避這些狀況產生的衝突。
2.3.0+ 新增
在有些狀況下,咱們可能須要對一個 prop 進行「雙向綁定」。不幸的是,真正的雙向綁定會帶來維護上的問題,由於子組件能夠修改父組件,且在父組件和子組件都沒有明顯的改動來源。
這也是爲何咱們推薦以 update:myPropName
的模式觸發事件取而代之。舉個例子,在一個包含 title
prop 的假設的組件中,咱們能夠用如下方法表達對其賦新值的意圖:
ChildBox.vue
<template>
<input type="checkbox"
:checked="checked"
@change="$emit('update:checked', $event.target.checked)"/>
</template>
<script>
export default {
props: {
checked: Boolean
}
}
</script>
複製代碼
Index.vue
<template>
<div> <ChildBox :checked.sync="val"/> <!-- 解析後 --> <ChildBox :checked="val" @update:checked="data => (val = data)"/> </div> </template> 複製代碼
分析一下上面的代碼有什麼變化,父組件v-model
被 :checked.sync
替換掉。子組件因不適用v-model
,因此不須要model配置。change函數改成event.target.checked)。
藉助ustbhuangyi Vue.js技術揭祕。這裏只作總結比對,詳細分析過程可查看連接。
如下面代碼爲例:
let vm = new Vue({
el: '#app',
template: '<div>'
+ '<input v-model="message" placeholder="edit me">' +
'<p>Message is: {{ message }}</p>' +
'</div>',
data() {
return {
message: ''
}
}
})
複製代碼
在 input 元素上設置了 v-model
屬性,綁定了 message
,當咱們在 input 上輸入內容時,message
也會同時發生變化。
源碼generate函數:
function generate ( ast, options ) {
var state = new CodegenState(options);
var code = ast ? genElement(ast, state) : '_c("div")';
return {
render: ("with(this){return " + code + "}"),
staticRenderFns: state.staticRenderFns
}
}
複製代碼
對咱們的例子而言,最終生成的 render
代碼以下:
with(this) {
return _c('div',[_c('input',{
directives:[{
name:"model",
rawName:"v-model",
value:(message),
expression:"message"
}],
attrs:{"placeholder":"edit me"},
domProps:{"value":(message)},
on:{"input":function($event){
if($event.target.composing)
return;
message=$event.target.value
}}}),_c('p',[_v("Message is: "+_s(message))])
])
}
複製代碼
最終轉化爲:
<input
v-bind:value="message"
v-on:input="message=$event.target.value">
複製代碼
動態綁定了 input
的 value
指向了 messgae
變量,而且在觸發 input
事件的時候去動態把 message
設置爲目標值,這樣實際上就完成了數據雙向綁定了,因此說 v-model
實際上就是語法糖。
ustbhuangyi
在Vue.js 技術揭祕中也詳細的介紹v-model在組件中的實現原理,這裏就不過多的陳述了。
咱們瞭解到 v-model
是 Vue 雙向綁定的真正實現,但本質上就是一種語法糖,它便可以支持原生表單元素,也能夠支持自定義組件。在組件的實現中,咱們是能夠配置子組件接收的 prop
名稱,以及派發的事件名稱。
最後有一個問題 v-model
和 .sync
均可以實現數據雙向綁定的效果,那到底用哪一種更合理呢?歡迎回復闡述你的觀點。
祝學習進步
鄧文斌
2019年3月21日