最近 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日