Vue 组件上的v-model双向绑定原理解析
之前我们分析了Vue
中v-model
指令在普通表单元素上的使用原理(点击这里跳转),这一节我们继续分析v-model
指令在组件上的原理。
组件上的v-model原理
v-model
指令在组件上的编译过程的parse
阶段与在表单元素上一样(可以参考),与普通表单元素不同之处在于genCode
的阶段,在执行model
函数生成代码的时候,会执行genComponentModel
函数:
v-model编译阶段
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
......
} else if (tag === 'input' || tag === 'textarea') {
// 本案例进入这个逻辑,我们分析一下
genDefaultModel(el, value, modifiers)
} else if (!config.isReservedTag(tag)) {
// 非保留标签,说明是组件节点,执行genComponentModel
genComponentModel(el, value, modifiers)
// component v-model doesn't need extra runtime
return false
}
......
return true
}
export function genComponentModel (
el: ASTElement,
value: string,
modifiers: ?ASTModifiers
): ?boolean {
// 解析修饰符
const { number, trim } = modifiers || {}
const baseValueExpression = '$$v'
let valueExpression = baseValueExpression
// 有trim修饰符,进入下面逻辑,生成value表达式
if (trim) {
valueExpression =
`(typeof ${baseValueExpression} === 'string'` +
`? ${baseValueExpression}.trim()` +
`: ${baseValueExpression})`
}
// 有number修饰符,生成下面表达式
if (number) {
valueExpression = `_n(${valueExpression})`
}
// 解析 value,生成解析规范后的表达式
const assignment = genAssignmentCode(value, valueExpression)
// AST element上挂载model对象
el.model = {
value: `(${value})`,
expression: `"${value}"`,
callback: `function (${baseValueExpression}) {${assignment}}`
}
}
可以看到组件执行完genDirectives
解析model
指令后,会在AST element
节点上生成model
对象,这是与普通表单元素不同的地方。组件的v-model
在genCode
过程中,执行完genDirectives
后还有有一段逻辑,如下:
export function genData (el: ASTElement, state: CodegenState): string {
let data = '{'
// directives may mutate the el's other properties before they are generated.
// 解析model指令
const dirs = genDirectives(el, state)
if (dirs) data += dirs + ','
......
// component v-model
// 组件上的v-model,进入该逻辑,拼接生成下面代码字符串
if (el.model) {
data += `model:{value:${
el.model.value
},callback:${
el.model.callback
},expression:${
el.model.expression
}},`
}
到这个时候才生成了最终的代码字符串。
组件生成阶段
export function createComponent (
Ctor: Class<Component> | Function | Object | void,
data: ?VNodeData,
context: Component,
children: ?Array<VNode>,
tag?: string
): VNode | Array<VNode> | void {
// ...
// transform component v-model data into props & events
// 如果data上有model属性
if (isDef(data.model)) {
// 调用transformModel,传入的参数为组件构造器的options配置项
transformModel(Ctor.options, data)
}
// ...
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
return vnode
}
在创建组件的时候,有上面这样一段逻辑,当分析到节点上有model
对象的时候,会调用transformModel
函数,对v-model
对象做下转化:
// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel (options, data: any) {
// 找到model上的prop属性
const prop = (options.model && options.model.prop) || 'value'
// 找到model上的event事件
const event = (options.model && options.model.event) || 'input'
// 在data的props属性对象上添加prop属性值
;(data.props || (data.props = {}))[prop] = data.model.value
// 在data的on属性对象上添加event事件
const on = data.on || (data.on = {})
if (isDef(on[event])) {
on[event] = [data.model.callback].concat(on[event])
} else {
on[event] = data.model.callback
}
}
可以看到最终是将编译过程中生成的model
对象,解析成为value
属性和input
事件,扩展到组件构造器的options
配置项中。
以上可以得知,组件上v-model
指令的本质也是生成了value
属性和input
事件。
到此这篇关于Vue 组件上的v-model双向绑定原理的文章就介绍到这了,更多相关Vue v-model双向绑定内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341