本文来自「Vue 虚拟实验室」的小伙伴,本文详细讲解了 v-model 的使用
@xyjwyq
在 Vue 中 v-model 指令的使用场景,主要分为两种:
1. 用于一些表单元素;
2. 自定义组件;
下面,针对这两种场景,进行一些总结。
表单元素中使用 v-model
v-model 指令在表单元素上的使用,主要是 input、textarea 以及 select 元素,而 v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
• text 和 textarea 元素使用 value 属性和 input 事件;
• checkbox 和 radio 使用 checked 属性和 change 事件;
• select 字段将 value 作为 prop 并将 change 作为事件。
下面从基本使用,编译结果分析以及源码三部分进行理解
1、基本使用
value: {
{ value }}
2、编译结果
const tplCOmplier = require('vue-template-compiler')
const res = tplCOmplier.compile('')
console.log(res)
/**
* 编译成之后输出的render
with (this) {
return _c('input', {
// 该指令作用,是对输入法的一些校验,暂不考虑
directives: [{
name: "model",
rawName: "v-model",
value: (value),
expression: "value"
}],
attrs: {
"type": "text"
},
domProps: {
"value": (value)
},
on: {
"input": function ($event) {
if ($event.target.composing) return;
value = $event.target.value }
}
})
}
*/
从编译结果可以看出,在渲染时,会 对不同的表单元素,添加不同的属性和事件(由篇幅问题,不将编译结果一一列举);
3、源码
// src\platforms\web\compiler\directives\model.js
if (el.component) {
genComponentModel(el, value, modifiers)
// component v-model doesn't need extra runtime
return false
} else if (tag === 'select') {
genSelect(el, value, modifiers)
} else if (tag === 'input' && type === 'checkbox') {
genCheckboxModel(el, value, modifiers)
} else if (tag === 'input' && type === 'radio') {
genRadioModel(el, value, modifiers)
} else if (tag === 'input' || tag === 'textarea') {
genDefaultModel(el, value, modifiers)
} else if (!config.isReservedTag(tag)) {
genComponentModel(el, value, modifiers)
// component v-model doesn't need extra runtime
return false
}
4、自定义 v-model
Vue.component('el-checkbox', {
template: ``,
props: ['checkValue'],
model: {
prop: 'checkValue',
event: 'changeEvent'
}
});
5、源码中自定义 v-model 的处理
function transformModel (options, data: any) {
// 若没有传递model配置,则默认为 value属性和input事件的语法糖
const prop = (options.model && options.model.prop) || 'value'
const event = (options.model && options.model.event) || 'input'
;(data.attrs || (data.attrs = {}))[prop] = data.model.value
const on = data.on || (data.on = {})
const existing = on[event]
const callback = data.model.callback
if (isDef(existing)) {
if (
Array.isArray(existing)
? existing.indexOf(callback) === -1
: existing !== callback
) {
on[event] = [callback].concat(existing)
}
} else {
on[event] = callback
}
}
推荐阅读:
让 Class 与 Style 动起来
动静结合 · Vue 模板
Vue 模板的功臣 · 指令