Vue知識點整理=^•ω•^=

這是我我的閱片(帖)無數以及在學習中總結的,但願能幫到你們,但願能給個星星Thanks♪(・ω・)ノjavascript

基礎篇

說說你對MVVM的理解

  • Model-View-ViewModel的縮寫,Model表明數據模型,View表明UI組件,ViewModel將Model和View關聯起來html

  • 數據會綁定到viewModel層並自動將數據渲染到頁面中,視圖變化的時候會通知viewModel層更新數據前端

MVC和MVVM的區別

  • MVC指的是Model-View-Controller,即模型-視圖-控制器。
  • MVC中的Control在MVVM中演變成viewModel.
  • MVVM經過數據來顯示視圖,而不是經過節點操做
  • MVVM主要解決了MVC中大量的DOM操做,使頁面渲染性能下降,加載速度慢,影響用戶體驗的問題

虛擬Dom

因爲在瀏覽器中操做DOM是很昂貴的。頻繁的操做DOM,會產生必定的性能問題。這就是虛擬Dom的產生緣由。vue

  • Virtual DOM本質就是用一個原生的JS對象去描述一個DOM節點。是對真實DOM的一層抽象。(也就是源碼中的VNode類,它定義在src/core/vdom/vnode.js中。)java

  • 虛擬 DOM 的實現原理主要包括如下 3 部分:node

    • 用 JavaScript 對象模擬真實 DOM 樹,對真實 DOM 進行抽象;
    • diff 算法 — 比較兩棵虛擬 DOM 樹的差別;
    • pach 算法 — 將兩個虛擬 DOM 對象的差別應用到真正的 DOM 樹。
  • key 是爲 Vue 中 vnode 的惟一標記,經過這個 key,咱們的 diff 操做能夠更準確、更快速web

key的做用

  • key是爲每一個vnode指定惟一的id,在同級vnode的Diff過程當中,能夠根據key快速的進行對比,來判斷是否爲相同節點,面試

  • 利用 key 的惟一性生成 map 對象來獲取對應節點,比遍歷方式更快,指定key後,能夠保證渲染的準確性(儘量的複用 DOM 元素。)正則表達式

爲何不建議用index做爲key?

  • 不建議 用index 做爲 key,和沒寫基本上沒區別,由於無論你數組的順序怎麼顛倒,index 都是 0, 1, 2 這樣排列,致使 Vue 會複用錯誤的舊子節點,作不少額外的工做算法

  • 通常都用數據中的惟一值,好比ID這種,或者實在不行使用UUID庫,  

diff的步驟

  • 用JS模擬真實DOM節點

  • 把虛擬DOM轉換成真實DOM插入頁面中

  • 發生變化時,比較兩棵樹的差別,生成差別對象

  • 根據差別對象更新真實DOM

Vue2.x響應式數據/雙向綁定原理

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 進行統一管理。

vue2.x中如何監測數組和對象變化?

  • Object經過Object.defineProperty結合遞歸就能實現

    • 比較麻煩就對了,Proxy就直接代理整個對象
  • Array的話 Vue將data中的數組進行了原型鏈重寫,指向了本身定義的數組原型方法。

  • 數組某些狀況下會不刷新視圖,咱們這樣解決

    • 當利用索引直接設置一個數組項時,例如vm.items[indexOfItem] = newValue
    //使用該方法進行更新視圖
    // vm.$set,Vue.set的一個別名 vm.$set(vm.items, indexOfItem, newValue) 複製代碼
    • 當修改數組的長度時,例如vm.items.length = newLength
    //使用該方法進行更新視圖
    // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue) 複製代碼

Proxy比Object.defineProperty好在哪?

Vue3.x改用Proxy替代Object.defineProperty

  • Object.defineProperty 只能劫持對象屬性的getter和setter方法

    • Proxy 是直接代理劫持整個對象
  • Object.definedProperty 不支持數組(能夠監聽數組,不過數組方法沒法監聽本身重寫),更準確的說是不支持數組的各類API(因此VUE重寫了數組方法

    • Proxy能夠直接監聽對象和數組的變化,而且有多達13種攔截方法。
  • 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 專屬 , 組件被銷燬時調用

初次渲染就會觸發的生命週期

  • beforeCreate() , created()
  • beforeMount() , mounted()

父組件和子組件之間的生命週期執行順序

組件的調用順序都是先父後子,渲染完成的順序是先子後父。 組件的銷燬操做是先父後子,銷燬完成的順序是先子後父。

加載渲染過程 子組件在父組件的beforeMount和Mounted之間渲染

- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
複製代碼

子組件更新過程

- 父beforeUpdate->子beforeUpdate->子updated->父updated
複製代碼

父組件更新過程

- 影響到子組件: - 父beforeUpdate -> 子beforeUpdate->子updated -> 父updted
- 不影響子組件: - 父beforeUpdate -> 父updated 複製代碼

銷燬過程

- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
複製代碼

什麼階段才能調用DOM

  • 在鉤子函數 mounted 被調用前,Vue 已經將編譯好的模板掛載到頁面上,因此在 mounted 中能夠訪問操做 DOM。

什麼階段能發起請求

  • 能夠在鉤子函數 created、beforeMount、mounted 中進行調用,由於在這三個鉤子函數中,data 已經建立,能夠將服務端端返回的數據進行賦值。

  • 可是推薦在 created 鉤子函數中調用異步請求,由於在 created 鉤子函數中調用異步請求有如下優勢:

    • 能更快獲取到服務端數據,減小頁面loading 時間;
    • ssr不支持 beforeMount 、mounted 鉤子函數,因此放在 created 中有助於一致性;

常規篇

computed 和 watch 的區別以及應用場景?

  • computed 依賴其餘的值,且具備緩存,緩存變化纔會更新

    • 只有它依賴的屬性值發生改變,下一次獲取 computed 的值時纔會從新計算 進行數值計算,而且依賴於其它數據 用他
  • watch 沒有緩存 監聽某一個值 變化進行一些操做

    • 數據變化時執行異步或開銷較大的操做時 用它

v-if和v-show的區別以及應用場景?

  • v-if 適用於在運行時不多改變條件,不須要頻繁切換條件的場景;

    • v-if移除Dom,對其進行銷燬;
  • v-show 則適用於須要很是頻繁切換條件的場景。

    • v-show是對元素進行display:none;

爲何 v-for 和 v-if 不建議用在一塊兒?

  • v-for優先級高於v-if,若是連在一塊兒使用的話會把v-if給每個元素都添加上,重複運行於每個v-for循環中,會形成性能浪費

  • 能夠將v-if寫在v-for的外層

v-model的實現

  • v-model是用來在表單控件或者組件上建立雙向綁定的

  • 他的本質是v-bind和v-on的語法糖

<input v-model="sth" />
// 等同於 <input :value="sth" @input="sth = $event.target.value" /> 複製代碼

Vue事件綁定原理是什麼?

  • 原生事件綁定是經過addEventListener綁定給真實元素的。

  • 組件事件綁定是經過Vue自定義的key$on實現的。

nextTick的實現原理是什麼?

在下次DOM更新循環結束以後執行的延遲迴調。

  • 根據執行環境分別嘗試採用 用微任務,再是宏任務
Promise的then -> MutationObserver的回調函數 -> setImmediate -> setTimeout 是否存在,找到存在的就調用他childrenRef
複製代碼

Vue2.x組件通訊有哪些方式?

過陣子會專門寫一篇Vue通訊 >v<

  • 父子組件通訊
- 事件機制(父->子props,子->父$on、$emit)
 - 獲取父子組件實例$parent、$children獲取實例的方式調用組件的屬性或者方法  - Provide、inject (不推薦使用,組件庫時很經常使用) 複製代碼
  • 兄弟組件通訊
- eventBus 這種方法經過一個空的 Vue實例做爲中央事件總線(事件中心),用它來觸發事件和監聽事件,從而實現任何組件間的通訊,包括父子、隔代、兄弟組件
  - 事件總線Vue.prototype.$bus = new Vue   - Vuex 複製代碼
  • 跨級組件通訊
- Vuex
 - $attrs父->子孫 / $listens子孫->獲父 複製代碼

Vue 的單向數據流

  • 全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外改變父級組件的狀態.

  • 子組件爲何不能夠修改父組件傳遞的Prop?

    • 這是爲了防止意外的改變父組件狀態,使得應用的數據流變得難以理解。
    • 若是破壞了單向數據流,當應用複雜時,debug 的成本會很是高。

組件中的data爲何是一個函數?

由於組件是用來複用的,且 JS 裏對象是引用關係,若是組件中 data 是一個對象,那麼這樣做用域沒有隔離,子組件中的 data 屬性值會相互影響,若是組件中 data 選項是一個函數,那麼每一個實例能夠維護一份被返回對象的獨立的拷貝,組件實例之間的 data 屬性值不會互相影響;

  • 並且new Vue根組件基本不須要複用,所以不須要以函數方式返回

VUE模板編譯原理?

  • 簡單來講

    • 1.解析模板 生成語法樹

    • 2.對語法樹進行標記,用來作虛擬Dom的優化

    • 3.將語法樹轉換爲可執行代碼

  • 細細細

  • 第一步將模版字符串轉換成element ASTs(解析器) 首先解析模版,生成AST語法樹(一種用JavaScript對象的形式來描述整個模板)。 使用大量的正則表達式對模板進行解析,遇到標籤、文本的時候都會執行對應的鉤子進行相關處理。

  • 第二步是對AST進行靜態節點標記,主要用來作虛擬DOM的渲染優化(優化器) 那麼優化過程就是深度遍歷AST樹,按照相關條件對樹節點進行標記,用來作虛擬DOM的渲染優化

  • 第三步是使用element ASTs生成render函數代碼字符串(代碼生成器) 編譯的最後一步是將優化後的AST樹轉換爲可執行的代碼。

Vue中 v-html 有什麼做用?會致使什麼問題?

  • v-html能夠用來識別HTML標籤並渲染出去

  • 致使問題: 在網站上動態渲染任意Html,很容易致使受到Xss攻擊,因此只能在可信內容上使用v-html,且永遠不能用於用戶提交的內容上

  • XSS防範手段

    • 設置Cookie httpOnly爲嚴格模式 , 禁止Javascript經過document.cookie得到
    • 對全部的輸入作嚴格的校驗尤爲是在服務器端,過濾掉任何不合法的輸入,好比手機號必須是數字,一般能夠採用正則表達式.
    • 轉義單引號,雙引號,尖括號等特殊字符,
    • 淨化和過濾掉沒必要要的html標籤,腳本的a標籤的href或者onclick等,
    • 配置白名單CSP,阻止白名單之外的資源加載和運行

什麼是 什麼是 mixin ?

  • 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 / history 兩種模式有什麼區別?

  • 最明顯的是在顯示上,hash模式的URL中會夾雜着#號,而history沒有。

  • Vue底層對它們的實現方式不一樣。

    • hash模式是依靠onhashchange事件(監聽location.hash的改變)
    • history模式是主要是依靠的HTML5 history中新增的兩個方法
      • pushState()能夠改變url地址且不會發送請求
      • replaceState()能夠讀取歷史記錄棧,還能夠對瀏覽器記錄進行修改。
  • 當真正須要經過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篇

VueX是什麼?

  • Vuex 相似 Redux 的狀態管理器,用來管理Vue的全部組件狀態。

    • state 定義了應用狀態的數據結構,能夠在這裏設置默認的初始狀態

      • 圖書館
    • mutations 同步操做,更改store狀態

      • 圖書管理員
    • actions 用於提交 mutation,而不是直接變動狀態,能夠包含任意異步操做

      • 借書卡,借書動做
    • Module 容許將單一的 Store 拆分爲多個 store 且同時保存在單一的狀態樹中。

      • 圖書館的樓層,小圖書館就不須要vuex了 o.o
    • Getter 處理一些比較複雜的函數

      • 圖書館的電腦?
    • component 組件

      • 借書人

    以上是我便於快速理解的 看着玩就行了ヽ(・ω・´メ)

Vuex 使用單一狀態樹,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。 ——Vuex官方文檔

什麼狀況下使用 Vuex?

  • 若是應用夠簡單,最好不要使用 Vuex,一個簡單的 store 模式便可

  • 須要構建一箇中大型單頁應用時,使用Vuex能更好地在組件外部管理狀態

Vuex和單純的全局對象有什麼區別?

  • Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。

  • 不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。

爲何不直接分發mutation,而要經過分發action以後提交 mutation變動狀態

  • mutation 必須同步執行,咱們能夠在 action 內部執行異步操做
  • 能夠進行一系列的異步操做,而且經過提交 mutation 來記錄 action 產生的反作用(即狀態變動)

我以爲把同步異步分開好維護好管理吧

vuex的action有返回值嗎?返回的是什麼?

  • store.dispatch 能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise

  • Action 一般是異步的,要知道 action 何時結束或者組合多個 action以處理更加複雜的異步流程,能夠經過定義action時返回一個promise對象,就能夠在派發action的時候就能夠經過處理返回的 Promise處理異步流程

一個 store.dispatch 在不一樣模塊中能夠觸發多個 action 函數。在這種狀況下,只有當全部觸發函數完成後,返回的 Promise 纔會執行。

Vue.observable(簡易版VueX)

  • 2.6.0 新增 用法:讓一個對象可響應,利用Vue.observable實現一個簡易的 vuex
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  } } 複製代碼
  • 使用vuex
<template>
 <div>  {{ userInfo.name }}  </div> </template> <script> import { store, mutations } from '../store' export default {  computed: {  userInfo() {  return store.userInfo  }  },  created() {  mutations.setUserInfo({  name: '子君'  })  } } </script> 複製代碼

性能優化篇

提升首頻加載速度

  • Vue-Router路由懶加載(利用Webpack的代碼切割)
  • 使用CDN加速,將通用的庫從vendor進行抽離
  • Nginx的gzip壓縮
  • Vue異步組件
  • 服務端渲染SSR
  • 若是使用了一些UI庫,採用按需加載
  • Webpack開啓gzip壓縮
  • 若是首屏爲登陸頁,能夠作成多入口
  • Service Worker緩存文件處理
  • 使用link標籤的rel屬性設置 prefetch(這段資源將會在將來某個導航或者功能要用到,可是本資源的下載順序權重比較低,prefetch一般用於加速下一次導航)、preload(preload將會把資源得下載順序權重提升,使得關鍵數據提早下載好,優化頁面打開速度)

keep-alive

  • 能夠在組件切換時 ,保留組件狀態,避免從新渲染 , 緩存在內存
<transition>
 <keep-alive>  <component v-bind:is="currentTabComponent"></component>  //<router-view><router-view>  </keep-alive> </transition> 複製代碼

v-cloak 網速慢時用

  • 網速慢的狀況下,在使用vue綁定數據的時候,渲染頁面時會出現變量閃爍
  • 能夠解決閃爍,可是會出現白屏,這樣能夠結合骨架屏使用
<div class="#app" v-cloak>
 <p>{{value.name}}</p> </div> 複製代碼

v-once 只渲染一次,且不會改變

<span v-once> 這時只須要加載一次的標籤</span> 複製代碼

路由懶加載/組件懶加載

component:()=>import('xxx')
複製代碼

圖片懶加載Vue-lazyload

over 邊複習邊調整邊總結,爲了面試能過沖沖沖啊

相關文章
相關標籤/搜索