# vue源码 v-model
# 本质
v-model
会有对应的directives属性描述指令相关信息genData
/compiler/codegen/index.js- 是通过监听表单控件input事件去影响自身的value值
<input v-model="value" type="text" />
<input :value="value" @input="(e)=>{this.value = e.target.value}" type="text"/>
- 父子组件通信的语法糖
- 默认利用
value
的prop
和input
事件
- 默认利用
# 源码相关
- 对模版里面的各种属性进行处理并返回拼接好的字符串
export function genData (el: ASTElement, state: CodegenState): string {
let data = '{'
...
// component v-model
if (el.model) {
data += `model:{value:${
el.model.value
},callback:${
el.model.callback
},expression:${
el.model.expression
}},`
}
...
genDirectives
遍历解析指令对象,最终以directives:['..']
包裹的字符串返回
function genDirectives (el: ASTElement, state: CodegenState): string | void {
const dirs = el.directives
if (!dirs) return
let res = 'directives:['
let hasRuntime = false
let i, l, dir, needRuntime
for (i = 0, l = dirs.length; i < l; i++) {
dir = dirs[i]
needRuntime = true
const gen: DirectiveFunction = state.directives[dir.name]
...
model
/compiler/directives/model.js- 对表单控件的ast树进行进一步的处理
export default function model (
el: ASTElement,
dir: ASTDirective,
_warn: Function
): ?boolean {
warn = _warn
const value = dir.value
const modifiers = dir.modifiers
const tag = el.tag
const type = el.attrsMap.type
if (process.env.NODE_ENV !== 'production') {
// inputs with type="file" are read only and setting the input's
// value will throw an error.
if (tag === 'input' && type === 'file') {
warn(
`<${el.tag} v-model="${value}" type="file">:\n` +
`File inputs are read only. Use a v-on:change listener instead.`,
el.rawAttrsMap['v-model']
)
}
}
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
} else if (process.env.NODE_ENV !== 'production') {
warn(
`<${el.tag} v-model="${value}">: ` +
`v-model is not supported on this element type. ` +
'If you are working with contenteditable, it\'s recommended to ' +
'wrap a library dedicated for that purpose inside a custom component.',
el.rawAttrsMap['v-model']
)
}
// ensure runtime directive metadata
return true
}
genDefaultModel
...
addProp(el, 'value', `(${value})`) // 添加value
addHandler(el, event, code, null, true) // 添加事件
if (trim || number) {
addHandler(el, 'blur', '$forceUpdate()')
}
...