[Vue源碼分析] v-model實現原理


前言:
我們都知道使用v-model可以實現數據的雙向綁定,及實現數據的變化驅動dom的更新,dom的更新影響數據的變化。那么v-model是怎么實現這一原理的呢?接下來探索一下這部分的源碼。

結論可直接看文末

前期准備
①:vue2.5.2源碼(用於閱讀、查看關聯等)
②:建立vue demo,創建包含v-model指令的實例(用於debugger)
以下為demo:


genDirectives
在模板的編譯階段, v-model跟其他指令一樣,會被解析到 el.directives 中,之后會通過genDirectives方法處理這些指令,genDirectives方法位於src/compiler/codegen/index.js中:

我們去到之前建立的demo,找到demo中node_modules/vue/dist/vue.esm.js下的genDirectives方法,打上debugger,如圖:

可以看到傳進來的el是ast語法樹,el.directives是el上的指令,如下:


回到genDirectives源碼,循環指令時都執行了const gen: DirectiveFunction = state.directives[dir.name]這個方法,state.directives是什么?
當遍歷到v-model的時候,dir.name為model,對應的state.directives[dir.name]相當於state.directives[model],directives的定義位於src/platforms/web/compiler/directives/index.js 中:

本次分析的v-model,對應的也就是model方法,也就是其實!!gen(el, dir, state.warn)執行的是model方法,!!用於將返回值轉為Boolean類型,model的定義位於index同目錄下。

model

model方法根據傳入的參數對tag的類型進行判斷,調用不同的處理邏輯,本demo中tag的類型為input,所以會執行genDefaultModel方法,為了節約時間,就不去源碼中找了,藏得比較深,直接在demo引用的單文件源碼vue.esm.js中搜索genDefaultModel。

genDefaultModel
發現定義如下,打上debugger,以便調試:

通過控制台查看變量信息,可以看到:

可以看到里邊的genAssignmentCode(value, valueExpression)在此demo中相當於genAssignmentCode("msg", ""$event.target.value""),執行此方法后返回的是一個字符串:msg=$event.target.value,后來命中了needCompositionGuard,所以code變成了if($event.target.composing)return;msg=$event.target.value,if($event.target.composing)return;的作用是不記錄用戶未確定的輸入,比如:

注釋掉if(needCompositionGuard)的話用戶沒確定的也會展示,如圖:

隨后會依次執行以下兩個方法:


addProp
先注釋掉addHandler,避免對研究此方法產生影響。

可以看到此方法的功能為給el添加props,首先判斷el上有沒有props,如果沒有的話創建props並賦值為一個空數組,隨后拼接對象並推到props中,代碼在此demo中相當於push了{name: "value", value: "(msg)"},打印一下這番操作后的el,可以看到添加了props的el的結構如下:

這個方法其實是在input上動態綁定了value,此時,原本的<input v-model="msg">相當於變成了<input v-bind:value="msg">,隨后繼續執行addHandler。

addHandler
以下僅包含關鍵代碼,打上debugger以便查看數據。

控制台查看el的debuuger結果:

可以看到比執行addHandler之前,el上多了events,可以得知這個方法主要給el 添加了事件處理,在此demo中的話相當於在 input 上綁定了 input 事件。

總結:
也就是說,到此為止,原本的<input v-model="msg">相當於變成了<input v-bind:value="msg" v-on:input="msg=$event.target.value">,當用戶輸入的使用觸發msg=$event.target.value進而更新msg,msg通過v-bind綁定到輸入框的value上。
即,以下兩份代碼其實是一個意思。
第一份:

第二份

————————————————
版權聲明:本文為CSDN博主「ECMAScripter」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/fabulous1111/article/details/85265503


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM