Vue?組件上的v-model雙向綁定原理解析
之前我們分析了Vue
中v-model
指令在普通表單元素上的使用原理(點(diǎn)擊這里跳轉(zhuǎn)),這一節(jié)我們繼續(xù)分析v-model
指令在組件上的原理。
組件上的v-model原理
v-model
指令在組件上的編譯過程的parse
階段與在表單元素上一樣(可以參考),與普通表單元素不同之處在于genCode
的階段,在執(zhí)行model
函數(shù)生成代碼的時(shí)候,會(huì)執(zhí)行genComponentModel
函數(shù):
v-model編譯階段
export default function model ( el: ASTElement, dir: ASTDirective, _warn: Function ): ?boolean { warn = _warn // 解析指令對(duì)象的值、修飾符、標(biāo)簽、類型 const value = dir.value const modifiers = dir.modifiers const tag = el.tag const type = el.attrsMap.type ...... } else if (tag === 'input' || tag === 'textarea') { // 本案例進(jìn)入這個(gè)邏輯,我們分析一下 genDefaultModel(el, value, modifiers) } else if (!config.isReservedTag(tag)) { // 非保留標(biāo)簽,說明是組件節(jié)點(diǎn),執(zhí)行g(shù)enComponentModel 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修飾符,進(jìn)入下面邏輯,生成value表達(dá)式 if (trim) { valueExpression = `(typeof ${baseValueExpression} === 'string'` + `? ${baseValueExpression}.trim()` + `: ${baseValueExpression})` } // 有number修飾符,生成下面表達(dá)式 if (number) { valueExpression = `_n(${valueExpression})` } // 解析 value,生成解析規(guī)范后的表達(dá)式 const assignment = genAssignmentCode(value, valueExpression) // AST element上掛載model對(duì)象 el.model = { value: `(${value})`, expression: `"${value}"`, callback: `function (${baseValueExpression}) {${assignment}}` } }
可以看到組件執(zhí)行完genDirectives
解析model
指令后,會(huì)在AST element
節(jié)點(diǎn)上生成model
對(duì)象,這是與普通表單元素不同的地方。組件的v-model
在genCode
過程中,執(zhí)行完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,進(jìn)入該邏輯,拼接生成下面代碼字符串 if (el.model) { data += `model:{value:${ el.model.value },callback:${ el.model.callback },expression:${ el.model.expression }},` }
到這個(gè)時(shí)候才生成了最終的代碼字符串。
組件生成階段
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)) { // 調(diào)用transformModel,傳入的參數(shù)為組件構(gòu)造器的options配置項(xiàng) 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 }
在創(chuàng)建組件的時(shí)候,有上面這樣一段邏輯,當(dāng)分析到節(jié)點(diǎn)上有model
對(duì)象的時(shí)候,會(huì)調(diào)用transformModel
函數(shù),對(duì)v-model
對(duì)象做下轉(zhuǎn)化:
// 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屬性對(duì)象上添加prop屬性值 ;(data.props || (data.props = {}))[prop] = data.model.value // 在data的on屬性對(duì)象上添加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
對(duì)象,解析成為value
屬性和input
事件,擴(kuò)展到組件構(gòu)造器的options
配置項(xiàng)中。
以上可以得知,組件上v-model
指令的本質(zhì)也是生成了value
屬性和input
事件。
到此這篇關(guān)于Vue 組件上的v-model雙向綁定原理的文章就介紹到這了,更多相關(guān)Vue v-model雙向綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue多組件倉(cāng)庫(kù)開發(fā)與發(fā)布詳解
這篇文章主要介紹了Vue多組件倉(cāng)庫(kù)開發(fā)與發(fā)布詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02vue項(xiàng)目啟動(dòng)命令個(gè)人學(xué)習(xí)記錄
最近想要學(xué)習(xí)vue,正好看到資料,如何通過命令創(chuàng)建vue項(xiàng)目的方法,就留個(gè)筆記,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目啟動(dòng)命令的相關(guān)資料,需要的朋友可以參考下2023-02-02vue+video.js視頻播放、視頻切換、視頻斷點(diǎn)分段上傳功能
本次需求是做一個(gè)視頻列表,點(diǎn)擊視頻列表播放對(duì)應(yīng)視頻;同時(shí)要求實(shí)現(xiàn)斷點(diǎn)分段上傳大文件(視頻)的功能,今天通過本文給大家講解下vue+video.js視頻播放、視頻切換、視頻斷點(diǎn)分段上傳功能,感興趣的朋友一起看看吧2022-12-12vue中控制mock在開發(fā)環(huán)境使用,在生產(chǎn)環(huán)境禁用方式
這篇文章主要介紹了vue中控制mock在開發(fā)環(huán)境使用,在生產(chǎn)環(huán)境禁用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue項(xiàng)目打包清除console.log的四種方法總結(jié)
大家在項(xiàng)目開發(fā)的時(shí)候,需要看看一些后端接口返回的結(jié)果,會(huì)多次使用console.log項(xiàng)目開發(fā)完成打包的時(shí)候,發(fā)現(xiàn)控制臺(tái)一堆的console.log,非常頭疼,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目打包清除console.log的四種方法,需要的朋友可以參考下2023-04-04