這是我我的閱片(帖)無數以及在學習中總結的,但願能幫到你們,但願能給個星星Thanks♪(・ω・)ノjavascript
Model-View-ViewModel的縮寫,Model表明數據模型,View表明UI組件,ViewModel將Model和View關聯起來html
數據會綁定到viewModel層並自動將數據渲染到頁面中,視圖變化的時候會通知viewModel層更新數據前端
「因爲在瀏覽器中操做DOM是很昂貴的。頻繁的操做DOM,會產生必定的性能問題。這就是虛擬Dom的產生緣由。」vue
Virtual DOM本質就是用一個原生的JS對象去描述一個DOM節點。是對真實DOM的一層抽象。(也就是源碼中的VNode類,它定義在src/core/vdom/vnode.js中。)java
虛擬 DOM 的實現原理主要包括如下 3 部分:node
key 是爲 Vue 中 vnode 的惟一標記,經過這個 key,咱們的 diff 操做能夠更準確、更快速web
key是爲每一個vnode指定惟一的id,在同級vnode的Diff過程當中,能夠根據key快速的進行對比,來判斷是否爲相同節點,面試
利用 key 的惟一性生成 map 對象來獲取對應節點,比遍歷方式更快,指定key後,能夠保證渲染的準確性(儘量的複用 DOM 元素。)正則表達式
不建議 用index 做爲 key,和沒寫基本上沒區別,由於無論你數組的順序怎麼顛倒,index 都是 0, 1, 2 這樣排列,致使 Vue 會複用錯誤的舊子節點,作不少額外的工做算法
通常都用數據中的惟一值,好比ID這種,或者實在不行使用UUID庫,
用JS模擬真實DOM節點
把虛擬DOM轉換成真實DOM插入頁面中
發生變化時,比較兩棵樹的差別,生成差別對象
根據差別對象更新真實DOM
Vue 數據雙向綁定主要是指:「數據變化更新視圖,視圖變化更新數據」。其中,View變化更新Data,能夠經過事件監聽的方式來實現,因此 Vue數據雙向綁定的工做主要是如何根據Data變化更新View。
當你把一個普通的 JavaScript 對象傳入 Vue 實例做爲 data 選項,Vue 將遍歷此對象全部的屬性,並使用 Object.defineProperty 把這些屬性所有轉爲 getter/setter。
getter/setter 對用戶來講是不可見的,可是在內部它們讓 Vue 可以追蹤依賴,在屬性被訪問和修改時通知變動。
每一個組件實例都對應一個 watcher 實例,它會在組件渲染的過程當中把「接觸」過的數據 屬性 記錄爲依賴。以後當依賴項的 setter 觸發時,會通知 watcher,從而使它關聯的組件從新渲染。
採用數據劫持結配合發佈者-訂閱者模式的方法,經過Object.defineProperty()來劫持各個屬性的getter、setter屬性,在數據變更後,在數據發生變化的時候,發佈消息給依賴收集器Dep,去通知觀察者Watcher,作出對應的回調函數去更新視圖。
解析器 Compile:解析 Vue 模板指令,將模板中的變量都替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,調用更新函數進行數據更新。
監聽器 Observer:對數據對象進行遍歷,包括子屬性對象的屬性,利用 Object.defineProperty() 對屬性都加上 setter 和 getter。這樣的話,給這個對象的某個值賦值,就會觸發 setter,那麼就能監聽到了數據變化。
訂閱者 Watcher:Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑 ,主要的任務是訂閱 Observer 中的屬性值變化的消息,當收到屬性值變化的消息時,觸發解析器 Compile 中對應的更新函數。每一個組件實例都有相應的 watcher 實例對象,它會在組件渲染的過程當中把屬性記錄爲依賴,以後當依賴項的 setter 被調用時,會通知 watcher 從新計算,從而導致它關聯的組件得以更新——這是一個典型的觀察者模式訂閱器
Dep:訂閱器採用 發佈-訂閱 設計模式,用來收集訂閱者 Watcher,對監聽器 Observer 和 訂閱者 Watcher 進行統一管理。
Object經過Object.defineProperty結合遞歸就能實現
Array的話 Vue將data中的數組進行了原型鏈重寫,指向了本身定義的數組原型方法。
數組某些狀況下會不刷新視圖,咱們這樣解決
//使用該方法進行更新視圖
// vm.$set,Vue.set的一個別名 vm.$set(vm.items, indexOfItem, newValue) 複製代碼
//使用該方法進行更新視圖
// Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue) 複製代碼
「Vue3.x改用Proxy替代Object.defineProperty」
Object.defineProperty 只能劫持對象屬性的getter和setter方法
Object.definedProperty 不支持數組(能夠監聽數組,不過數組方法沒法監聽本身重寫),更準確的說是不支持數組的各類API(因此VUE重寫了數組方法
Proxy 會返回一個代理對象,咱們只須要操做新對象便可,而 Object.defineProperty 只能遍歷對象屬性直接修改
Object.definedProperty惟一比Proxy好的一點就是兼容性,不過相信Proxy新標準將受到瀏覽器廠商重點持續的性能優化
初始化 (create)--- 組件掛載(mount)-----組件更新 (update)--- 銷燬(destroy)
生命週期 | 發生了什麼 |
---|---|
beforeCreate | 初始化界面前 : 在當前階段data、methods、computed以及watch上的數據和方法都不能被訪問 |
created | 初始化界面後 : 在實例建立完成後發生,當前階段已經完成了數據觀測,也就是可使用數據,更改數據,在這裏更改數據不會觸發updated函數,也就是不會更新視圖,SSR能夠放這裏。 |
beforeMount | 掛載前 :完成模板編譯,虛擬Dom已經建立完成,即將開始渲染。在此時也能夠對數據進行更改,不會觸發updated |
mounted | 掛在完成 : 將編譯好的模板掛載到頁面 (虛擬DOM掛載) ,能夠在這進行異步請求以及DOM節點的訪問,在vue用$ref操做 |
beforeUpdate | 更新數據前 : 組件數據更新以前調用,數據都是新的,頁面上數據都是舊的 組件即將更新,準備渲染頁面 , 能夠在當前階段進行更改數據,不會形成重渲染 |
updated | 組件更新後 : render從新渲染 , 此時數據和界面都是新的 ,要注意的是避免在此期間更改數據,由於這可能會致使無限循環的更新 |
beforeDestroy | 組件卸載前 : 實例銷燬以前,在當前階段實例徹底能夠被使用,咱們能夠在這時進行善後收尾工做,好比清除計時器 |
destroyed | 組件卸載後 : 組件已被拆解,數據綁定被卸除,監聽被移出,子實例也通通被銷燬。 |
activited | keep-alive 專屬 , 組件被激活時調用 |
deactivated | keep-alive 專屬 , 組件被銷燬時調用 |
組件的調用順序都是先父後子,渲染完成的順序是先子後父。 組件的銷燬操做是先父後子,銷燬完成的順序是先子後父。
加載渲染過程 子組件在父組件的beforeMount和Mounted之間渲染
- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
複製代碼
子組件更新過程
- 父beforeUpdate->子beforeUpdate->子updated->父updated
複製代碼
父組件更新過程
- 影響到子組件: - 父beforeUpdate -> 子beforeUpdate->子updated -> 父updted - 不影響子組件: - 父beforeUpdate -> 父updated 複製代碼
銷燬過程
- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
複製代碼
能夠在鉤子函數 created、beforeMount、mounted 中進行調用,由於在這三個鉤子函數中,data 已經建立,能夠將服務端端返回的數據進行賦值。
可是推薦在 created 鉤子函數中調用異步請求,由於在 created 鉤子函數中調用異步請求有如下優勢:
computed 依賴其餘的值,且具備緩存,緩存變化纔會更新
watch 沒有緩存 監聽某一個值 變化進行一些操做
v-if 適用於在運行時不多改變條件,不須要頻繁切換條件的場景;
v-show 則適用於須要很是頻繁切換條件的場景。
v-for優先級高於v-if,若是連在一塊兒使用的話會把v-if給每個元素都添加上,重複運行於每個v-for循環中,會形成性能浪費
能夠將v-if寫在v-for的外層
v-model是用來在表單控件或者組件上建立雙向綁定的
他的本質是v-bind和v-on的語法糖
<input v-model="sth" />
// 等同於 <input :value="sth" @input="sth = $event.target.value" /> 複製代碼
原生事件綁定是經過addEventListener綁定給真實元素的。
組件事件綁定是經過Vue自定義的key$on實現的。
在下次DOM更新循環結束以後執行的延遲迴調。
Promise的then -> MutationObserver的回調函數 -> setImmediate -> setTimeout 是否存在,找到存在的就調用他childrenRef
複製代碼
過陣子會專門寫一篇Vue通訊 >v<
- 事件機制(父->子props,子->父$on、$emit) - 獲取父子組件實例$parent、$children獲取實例的方式調用組件的屬性或者方法 - Provide、inject (不推薦使用,組件庫時很經常使用) 複製代碼
- eventBus 這種方法經過一個空的 Vue實例做爲中央事件總線(事件中心),用它來觸發事件和監聽事件,從而實現任何組件間的通訊,包括父子、隔代、兄弟組件
- 事件總線Vue.prototype.$bus = new Vue - Vuex 複製代碼
- Vuex - $attrs父->子孫 / $listens子孫->獲父 複製代碼
全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外改變父級組件的狀態.
子組件爲何不能夠修改父組件傳遞的Prop?
由於組件是用來複用的,且 JS 裏對象是引用關係,若是組件中 data 是一個對象,那麼這樣做用域沒有隔離,子組件中的 data 屬性值會相互影響,若是組件中 data 選項是一個函數,那麼每一個實例能夠維護一份被返回對象的獨立的拷貝,組件實例之間的 data 屬性值不會互相影響;
簡單來講
1.解析模板 生成語法樹
2.對語法樹進行標記,用來作虛擬Dom的優化
3.將語法樹轉換爲可執行代碼
細細細
第一步將模版字符串轉換成element ASTs(解析器) 首先解析模版,生成AST語法樹(一種用JavaScript對象的形式來描述整個模板)。 使用大量的正則表達式對模板進行解析,遇到標籤、文本的時候都會執行對應的鉤子進行相關處理。
第二步是對AST進行靜態節點標記,主要用來作虛擬DOM的渲染優化(優化器) 那麼優化過程就是深度遍歷AST樹,按照相關條件對樹節點進行標記,用來作虛擬DOM的渲染優化
第三步是使用element ASTs生成render函數代碼字符串(代碼生成器) 編譯的最後一步是將優化後的AST樹轉換爲可執行的代碼。
v-html能夠用來識別HTML標籤並渲染出去
致使問題: 在網站上動態渲染任意Html,很容易致使受到Xss攻擊,因此只能在可信內容上使用v-html,且永遠不能用於用戶提交的內容上
XSS防範手段
Mixin 使咱們可以爲 Vue 組件編寫可插拔和可重用的功能。若是你但願再多個組件之間重用一組組件選項,例如生命週期 hook、 方法等,則能夠將其編寫爲 mixin,並在組件中簡單的引用它。
而後將 mixin 的內容合併到組件中。若是你要在 mixin 中定義生命週期 hook,那麼它在執行時將優化於組件自已的 hook。
const mixin1 = {mounted() {console.log(2);}};
const mixin2 = {mounted() { console.log(3); }}; const extend1 ={mounted() {console.log(4);}} export default{ extends:extend1, mixins: [mixin1, mixin2], mounted() { console.log(1); } } //最終輸出 4 2 3 1 複製代碼
最明顯的是在顯示上,hash模式的URL中會夾雜着#號,而history沒有。
Vue底層對它們的實現方式不一樣。
當真正須要經過URL向後端發送HTTP請求的時候,好比常見的用戶手動輸入URL後回車,或者是刷新(重啓)瀏覽器,這時候history模式須要後端的支持。
由於history模式下,前端的URL必須和實際向後端發送請求的URL一致,例若有一個URL是帶有路徑path的(例如www.lindaidai.wang/blogs/id),若是後端沒有對這個路徑作處理的話,就會返回404錯誤。因此須要後端增長一個覆蓋全部狀況的候選資源,通常會配合前端給出的一個404頁面。
附上我用Node處理history問題的js代碼塊 >v<
// 其實就是用了箇中間件 -.-
let history = require('connect-history-api-fallback'); app.use(history()) 複製代碼
Vuex 相似 Redux 的狀態管理器,用來管理Vue的全部組件狀態。
state 定義了應用狀態的數據結構,能夠在這裏設置默認的初始狀態
mutations 同步操做,更改store狀態
actions 用於提交 mutation,而不是直接變動狀態,能夠包含任意異步操做
Module 容許將單一的 Store 拆分爲多個 store 且同時保存在單一的狀態樹中。
Getter 處理一些比較複雜的函數
component 組件
以上是我便於快速理解的 看着玩就行了ヽ(・ω・´メ)
Vuex 使用單一狀態樹,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。 ——Vuex官方文檔
若是應用夠簡單,最好不要使用 Vuex,一個簡單的 store 模式便可
須要構建一箇中大型單頁應用時,使用Vuex能更好地在組件外部管理狀態
Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。
不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。
我以爲把同步異步分開好維護好管理吧
store.dispatch 能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise
Action 一般是異步的,要知道 action 何時結束或者組合多個 action以處理更加複雜的異步流程,能夠經過定義action時返回一個promise對象,就能夠在派發action的時候就能夠經過處理返回的 Promise處理異步流程
一個 store.dispatch 在不一樣模塊中能夠觸發多個 action 函數。在這種狀況下,只有當全部觸發函數完成後,返回的 Promise 纔會執行。
store.js
import Vue from 'vue' // 經過Vue.observable建立一個可響應的對象 export const store = Vue.observable({ userInfo: {}, roleIds: [] }) // 定義 mutations, 修改屬性 export const mutations = { setUserInfo(userInfo) { store.userInfo = userInfo }, setRoleIds(roleIds) { store.roleIds = roleIds } } 複製代碼
<template>
<div> {{ userInfo.name }} </div> </template> <script> import { store, mutations } from '../store' export default { computed: { userInfo() { return store.userInfo } }, created() { mutations.setUserInfo({ name: '子君' }) } } </script> 複製代碼
<transition>
<keep-alive> <component v-bind:is="currentTabComponent"></component> //<router-view><router-view> </keep-alive> </transition> 複製代碼
<div class="#app" v-cloak>
<p>{{value.name}}</p> </div> 複製代碼
<span v-once> 這時只須要加載一次的標籤</span> 複製代碼
component:()=>import('xxx')
複製代碼
over 邊複習邊調整邊總結,爲了面試能過沖沖沖啊