vue的核心思想?
數據驅動
什麼是數據驅動?
數據驅動指的是視圖是由數據驅動生成,我們對視圖的修改不會直接操作DOM,而是修改數據。
模版和數據怎麼渲染成DOM的呢?
1. new Vue發生了什麼
Vue實際是一個類,只能通過new關鍵字初始化(在JavaScript中類是通過function實現的)
可以看到,new Vue會調用_init()
方法,並且將參數options傳給這個方法。
合併參數,把參數options賦值給vue實例的$options
在初始化的最後,檢測到如果有el屬性,則調用vm.$mount
方法掛載vm(vue實例),掛載的目的就是把模版渲染成DOM。
2. new Vue主要執行一些初始化的操作,Vue初始化主要乾了幾件事?
合併參數、初始化生命週期、初始化事件、初始化渲染、初始化data、props、computed、watcher等
3. 爲什麼在data中定義數據message可以直接通過this.message訪問到?
在初始化中有initState(vm)
初始化狀態,找到initState方法
initState方法主要是實現props,methods,data,watch,computed的初始化
如果data存在,會初始化data,看看初始化data的方法initData(vm)
初始化data做了哪些事?
- 先從vue實例vm的$options中取到data
let data = vm.$options.data
-
將data賦值給vm._data,
判斷data是不是一個function,如果是函數就調用getData
方法,將data()返回的值賦值給data變量,如果不是function就不處理data -
判斷最終的data是不是一個對象,如果不是對象就作出警告——data必須是一個對象
-
獲取data中的key,和props進行對比(就是說如果我在props中定義了一個id,就不能在data中定義id),不能重複的原因是因爲不管是data還是props他們的屬性最終都會掛載到vue實例上,通過this.id可以訪問到
-
最終會執行
首先理解Object.defineProperty()用法
Object.defineProperty()
的作用就是直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性
Object.defineProperty(obj, prop, desc)
這個方法接受3個參數:
- obj需要定義屬性的當前對象(在這裏就是傳入的vue實例對象vm)
- prop需要定義或修改的屬性名,(這裏就是傳入的props或者data的key)
- desc 屬性描述符 是一個對象更(這裏指的是sharePropertyDefinition對象)
在這裏定義了描述對象的屬性描述符:
enumerable: true
(可枚舉,就是是否出現在for…in或Object.keys中) configurable:true
(是否配置,能否刪除)
sourceKey是傳入的參數_data或者_prop字符串
上面的target是傳入的vue實例對象,通過set和get的方法寫入或讀取數據,
從上面可以看出訪問data上的id通過this.id
實際上是訪問了this._data.id
或this._props.id
4. Vue實例掛載的實現
以下是Runtime+compiler版本的$mount方法實現
$mount方法
這個方法在platform目錄下的多個目錄下文件中都有定義,因爲這個方法的實現是和平臺和構建方式都相關的。
- 首先緩存了Vue原型上的$mount方法,然後再重新定義該方法
爲什麼是重新定義呢?
因爲在runtime/index.js中已經定義了$mount
的方法,需要重新定義是因爲Runtime Only版本沒有$mount方法中的邏輯
- Runtime Only版本的$mount方法
這裏的query方法就是一個原生JavaScript API獲取DOM的方法 - Runtime Compiler版本的$mount方法
首先將el轉換爲DOM對象,然後對el做了限制,Vue不能掛載在body、html這樣的根節點上
然後判斷開發人員有沒有定義render方法,判斷有沒有寫template
如果template存在,再判斷template的類型,重新賦值template,判斷最後的template,編譯生成render函數
說到底就是看有沒有render函數,因爲vue最終只認render函數,如果有render函數就直接調用render函數,如果沒有就將模版編譯生成render函數
最後
最後調用調用緩存的mount方法(即走到了runtime/index.js裏面)
最後執行mountComponent
方法,這個方法做的事:如果沒有寫render函數,首先會將vm.$options.render賦值成一個空Node對象
vm.$options.render=createEmptyNode
, 然後會嘗試錯誤提示,就是如果你使用的是Runtime Only版本卻沒有寫render函數卻寫了template警告,或者即沒有寫render函數又沒有寫template警告。
5. render方法做了哪些事情
Vue的_render方法是實例的一個私有方法,用來把實例渲染成一個虛擬Node(_render方法定義在src/core/instance/render.js中)
我們平時在開發過程中手寫render函數的場景比較少,寫得比較多的是template模版,template模版會被編譯成render方法。
render函數的第一個參數是createElement(createElement是一個函數vm.$createElement
)
vm.$createElement
createElement方法是在src/core/vdom/create-element下定義的
在執行initRender方法時候會調用createElement方法
可以看到除了又一個vm.$createElement
方法外還定義了vm._c
方法,那這兩個方法有什麼區別,他們內部都調用了createElement方法,只是最後一個參數傳得不同:
vm._c
方法是模版被編譯成render方法時調用的vm.$createElement
方法是用戶手寫render函數時候調用的
總的來說:render方法最終是通過執行createElement方法並返回虛擬VNode(虛擬Node)