vue面試相關(guān)問題

目錄

1.深入淺出Vue響應(yīng)式原理

2.v-if、v-show區(qū)別
3.vue-router 有哪些模式? 區(qū)別是什么? 具體是怎么實現(xiàn)的

  1. vue-router導(dǎo)航守衛(wèi)

  2. vue組件通信

  3. diff算法

  4. Vue3 proxy

  5. vue.$set

  6. Vue是怎么重寫數(shù)組的

  7. Vue.nextTick()

  8. Key的作用

  9. slot插槽

  10. 為什么vue data屬性必須是一個函數(shù)

14.diff算法

  1. vue-router編程式導(dǎo)航

  2. vue中輸入框事件的使用——@input、@keyup.enter、@change、@blur

  3. 自定義指令(v-check、 v-focus)的方法有哪些?它有哪些鉤子函數(shù)?

  4. 自定義組件的v-model

  5. vue-router router-link組件的active-class屬性

  6. vue- router嵌套路由

  7. Vue中computed和method之間有什么不同點

  8. 要發(fā)送一個異步請求,應(yīng)該放在哪個生命周期

  9. vue和原生js的優(yōu)點分析

  10. 如果要新增一個屬性怎么實現(xiàn)響應(yīng)式

  11. 虛擬 DOM 有什么優(yōu)點和缺、點

  12. vue項目實現(xiàn)路由按需加載

  13. 為什么 vue 不建議在 action 中修改 state 而是在 mutation 中修改

  14. .vue是怎么渲染到頁面上的(源碼分析)

  15. vue項目中實現(xiàn)圖片懶加載

  16. vue3的新特性有了解過嗎

  17. vue項目優(yōu)化

1.深入淺出Vue響應(yīng)式原理

2.v-if、v-show區(qū)別

3.vue-router 有哪些模式? 區(qū)別是什么? 具體是怎么實現(xiàn)的

淺談vue-router原理
https://www.cnblogs.com/goloving/p/9147551.html

https://blog.csdn.net/wang1006008051/article/details/81805932

history和hash的區(qū)別
  1. hash路由在地址欄URL上有#,用 window.location.hash 讀取。而history路由沒有會好看一點
  2. 我們進(jìn)行回車刷新操作,hash路由會加載到地址欄對應(yīng)的頁面,而history路由一般就404報錯了(刷新是網(wǎng)絡(luò)請求,沒有后端準(zhǔn)備時會報錯)。
  3. hash路由支持低版本的瀏覽器,而history路由是HTML5新增的API。
    4.hash的特點在于它雖然出現(xiàn)在了URL中,但是不包括在http請求中,所以對于后端是沒有一點影響的,所以改變hash不會重新加載頁面,所以這也是單頁面應(yīng)用的必備。
    5.history運用了瀏覽器的歷史記錄棧,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法,它們提供了對歷史記錄進(jìn)行修改的功能,不過在進(jìn)行修改時,雖然改變了當(dāng)前的URL,但是瀏覽器不會馬上向后端發(fā)送請求。
    6.history的這種模式需要后臺配置支持。比如:當(dāng)我們進(jìn)行項目的主頁的時候,一切正常,可以訪問,但是當(dāng)我們刷新頁面或者直接訪問路徑的時候就會返回404,那是因為在history模式下,只是動態(tài)的通過js操作window.history來改變?yōu)g覽器地址欄里的路徑,并沒有發(fā)起http請求,但是當(dāng)我直接在瀏覽器里輸入這個地址的時候,就一定要對服務(wù)器發(fā)起http請求,但是這個目標(biāo)在服務(wù)器上又不存在,所以會返回404
總結(jié)

當(dāng)然啦,history 也不是樣樣都好。SPA 雖然在瀏覽器里游刃有余,但真要通過 URL 向后端發(fā)起 HTTP 請求時,兩者的差異就來了。尤其在用戶手動輸入 URL 后回車,或者刷新(重啟)瀏覽器的時候。

  1. hash 模式下,僅 hash 符號之前的內(nèi)容會被包含在請求中,如 http://www.abc.com,因此對于后端來說,即使沒有做到對路由的全覆蓋,也不會返回 404 錯誤。
  2. history 模式下,前端的 URL 必須和實際向后端發(fā)起請求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少對 /book/id 的路由處理,將返回 404 錯誤。Vue-Router 官網(wǎng)里如此描述:“不過這種模式要玩好,還需要后臺配置支持……所以呢,你要在服務(wù)端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源,則應(yīng)該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面?!?/li>
  3. 結(jié)合自身例子,對于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 開發(fā)場景,用 history 模式即可,只需在后端(Apache 或 Nginx)進(jìn)行簡單的路由配置,同時搭配前端路由的 404 頁面支持。

4. vue-router導(dǎo)航守衛(wèi)

https://zhuanlan.zhihu.com/p/54112006
應(yīng)用場景
https://www.cnblogs.com/baifangzi/p/14283463.html

5. vue組件通信

6. diff算法

7. Vue3 proxy

8. vue.$set

原理
https://www.jb51.net/article/146580.htm
源碼

export function set (target: Array<any> | Object, key: any, val: any): any {
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }  // 判斷目標(biāo)值是否為數(shù)組,并且key值是否為有效的數(shù)組索引
  if (Array.isArray(target) && isValidArrayIndex(key)) {  // 對比數(shù)組的key值和數(shù)組長度,取較大值設(shè)置為數(shù)組的長度
    target.length = Math.max(target.length, key)  // 替換目標(biāo)值
    target.splice(key, 1, val)
    return val
  }  // 如果目標(biāo)值是對象,并且key值是目標(biāo)值存在的有效key值,并且不是原型上的key值
  if (key in target && !(key in Object.prototype)) {  // 直接更改目標(biāo)值
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__ // 判斷目標(biāo)值是否為響應(yīng)式的
  if (target._isVue || (ob && ob.vmCount)) { // 如果是vue根實例,就警告
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  if (!ob) { // 如果目標(biāo)值不是響應(yīng)式的,那么值需要給對應(yīng)的key賦值
    target[key] = val
    return val
  }  // 其他情況,目標(biāo)值是響應(yīng)式的,就通過Object.defineProperty進(jìn)行數(shù)據(jù)監(jiān)聽
  defineReactive(ob.value, key, val)  // 通知更新dom操作
  ob.dep.notify()
  return val
}

大概流程

  1. 判斷目標(biāo)值是否為有效值,不是有效值直接停止

  2. 判斷是否為數(shù)組,并且key值是否為有效的key值
    如果是數(shù)組,就選擇數(shù)組的長度和key值取較大值作為數(shù)組的新的length值,并且替換目標(biāo)值splice方法,重寫了,所以執(zhí)行splice,會雙向數(shù)據(jù)綁定

  3. 判斷目標(biāo)值是否為響應(yīng)式的ob
    如果是vue實例,直接不行
    如果不是響應(yīng)式的數(shù)據(jù),就是普通的修改對象操作
    如果是響應(yīng)式數(shù)據(jù),那就通過Object.defineProperty進(jìn)行數(shù)據(jù)劫持

  4. 通知dom更新

9. Vue是怎么重寫數(shù)組的

// 緩存數(shù)組原型
const arrayProto = Array.prototype;
// 實現(xiàn) arrayMethods.__proto__ === Array.prototype
export const arrayMethods = Object.create(arrayProto);
// 需要進(jìn)行功能拓展的方法
const methodsToPatch = [
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse"
];

/**
 * Intercept mutating methods and emit events
 */
methodsToPatch.forEach(function(method) {
  // 緩存原生數(shù)組方法
  const original = arrayProto[method];
  def(arrayMethods, method, function mutator(...args) {
    // 執(zhí)行并緩存原生數(shù)組功能
    const result = original.apply(this, args);
    // 響應(yīng)式處理
    const ob = this.__ob__;
    let inserted;
    switch (method) {
    // push、unshift會新增索引,所以要手動observer
      case "push":
      case "unshift":
        inserted = args;
        break;
      // splice方法,如果傳入了第三個參數(shù),也會有索引加入,也要手動observer。
      case "splice":
        inserted = args.slice(2);
        break;
    }
    // 
    if (inserted) ob.observeArray(inserted);// 獲取插入的值,并設(shè)置響應(yīng)式監(jiān)聽
    // notify change
    ob.dep.notify();// 通知依賴更新
    // 返回原生數(shù)組方法的執(zhí)行結(jié)果
    return result;
  });
});

};

10. Vue.nextTick()

實現(xiàn)原理

/* @flow */
/* globals MutationObserver */

import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'

export let isUsingMicroTask = false

const callbacks = []
let pending = false

/**
 * 對所有callback進(jìn)行遍歷,然后指向響應(yīng)的回調(diào)函數(shù)
 * 使用 callbacks保證了可以在同一個tick內(nèi)執(zhí)行多次 nextTick,不會開啟多個異步任務(wù),而把這些異步任務(wù)都壓成一個同步任務(wù),在下一個 tick 執(zhí)行完畢。
*/

function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]( "i")
  }
}


let timerFunc
/*
* timerFunc 實現(xiàn)的就是根據(jù)當(dāng)前環(huán)境判斷使用哪種方式實現(xiàn)
* 就是按照 Promise.then和 MutationObserver以及setImmediate的優(yōu)先級來判斷,支持哪個就用哪個,如果執(zhí)行環(huán)境不支持,會采用setTimeout(fn, 0)代替;
*/

// 判斷是否支持原生 Promise
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
  // 不支持 Promise的話,再判斷是否原生支持 MutationObserver
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  // 新建一個 textNode的DOM對象,使用 MutationObserver 綁定該DOM并傳入回調(diào)函數(shù),在DOM發(fā)生變化的時候會觸發(fā)回調(diào),該回調(diào)會進(jìn)入主線程(比任務(wù)隊列優(yōu)先執(zhí)行)
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    // 此時便會觸發(fā)回調(diào)
    textNode.data = String(counter)
  }
  isUsingMicroTask = true
  // 不支持的 MutationObserver 的話,再去判斷是否原生支持 setImmediate
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  // Promise,MutationObserver, setImmediate 都不支持的話,最后使用 setTimeout(fun, 0)
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

// 該函數(shù)的作用就是延遲 cb 到當(dāng)前調(diào)用棧執(zhí)行完成之后執(zhí)行
export function nextTick (cb?: Function, ctx?: Object) {
  // 傳入的回調(diào)函數(shù)會在callbacks中存起來
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  // pending是一個狀態(tài)標(biāo)記,保證timerFunc在下一個tick之前只執(zhí)行一次
  if (!pending) {
    pending = true
    /**
    * timerFunc 實現(xiàn)的就是根據(jù)當(dāng)前環(huán)境判斷使用哪種方式實現(xiàn)
    * 就是按照 Promise.then和 MutationObserver以及setImmediate的優(yōu)先級來判斷,支持哪個就用哪個,如果執(zhí)行環(huán)境不支持,會采用setTimeout(fn, 0)代替;
    */
    timerFunc()
  }
  // 當(dāng)nextTick不傳參數(shù)的時候,提供一個Promise化的調(diào)用
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}
  1. nextTick接受一個回調(diào)函數(shù)時(當(dāng)不傳參數(shù)的時候,提供一個Promise化的調(diào)用),傳入的回調(diào)函數(shù)會在callbacks中存起來,根據(jù)一個狀態(tài)標(biāo)記 pending 來判斷當(dāng)前是否要執(zhí)行 timerFunc();
  2. timerFunc() 是根據(jù)當(dāng)前環(huán)境判斷使用哪種方式實現(xiàn),按照 Promise.thenMutationObserver以及setImmediate的優(yōu)先級來判斷,支持哪個就用哪個,如果執(zhí)行環(huán)境不支持,會采用setTimeout(fn, 0)代替;
  3. timerFunc()函數(shù)中會執(zhí)行 flushCallbacks函數(shù),flushCallbacks函數(shù)的作用就是對所有callback進(jìn)行遍歷,然后指向響應(yīng)的回調(diào)函數(shù)

總體來說:就是先判斷是否支持promise,如果支持promise。就通過Promise.resolve的方法,異步執(zhí)行方法,如果不支持promise,就判斷是否支持MutationObserver。如果支持,就通過MutationObserver(微異步)來異步執(zhí)行方法,如果MutationObserver還不支持,就通過setTimeout來異步執(zhí)行方法。

MutaionObserver通過創(chuàng)建新的節(jié)點,調(diào)用timerFunc方法,改變MutationObserver監(jiān)聽的節(jié)點變化,從而觸發(fā)異步方法執(zhí)行。

11. Key的作用

12. slot插槽

13. 為什么vue data屬性必須是一個函數(shù)

14.diff算法

視頻

15. vue-router編程式導(dǎo)航

官方文檔

16. vue中輸入框事件的使用——@input、@keyup.enter、@change、@blur

17. 自定義指令(v-check、 v-focus)的方法有哪些?它有哪些鉤子函數(shù)?

vue2.0
vue3.0
2.0與3.0主要區(qū)別為3.0的鉤子函數(shù)更全
2.0

  • bind:只調(diào)用一次,指令第一次綁定到元素時調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置。

  • inserted:被綁定元素插入父節(jié)點時調(diào)用 (僅保證父節(jié)點存在,但不一定已被插入文檔中)。

  • update:所在組件的 VNode 更新時調(diào)用,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變,也可能沒有。但是你可以通過比較更新前后的值來忽略不必要的模板更新 (詳細(xì)的鉤子函數(shù)參數(shù)見下)。

  • componentUpdated:指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用。

  • unbind:只調(diào)用一次,指令與元素解綁時調(diào)用。

3.0

  • created:在綁定元素的 attribute 或事件監(jiān)聽器被應(yīng)用之前調(diào)用。在指令需要附加須要在普通的 v-on 事件監(jiān)聽器前調(diào)用的事件監(jiān)聽器時,這很有用。

  • beforeMount:當(dāng)指令第一次綁定到元素并且在掛載父組件之前調(diào)用。

  • mounted:在綁定元素的父組件被掛載后調(diào)用。

  • beforeUpdate:在更新包含組件的 VNode 之前調(diào)用。

  • updated:在包含組件的 VNode 及其子組件的 VNode 更新后調(diào)用。

  • beforeUnmount:在卸載綁定元素的父組件之前調(diào)用

  • unmounted:當(dāng)指令與元素解除綁定且父組件已卸載時,只調(diào)用一次。

18. 自定義組件的v-model

19. vue-router router-link組件的active-class屬性

20. vue- router嵌套路由

21. Vue中computed和method之間有什么不同點

VUE中methods watch和compute的區(qū)別和聯(lián)系

22. 要發(fā)送一個異步請求,應(yīng)該放在哪個生命周期

23. vue和原生js的優(yōu)點分析

24. 如果要新增一個屬性怎么實現(xiàn)響應(yīng)式

this.$set(this.data,”key”,value’)

Vue.set(vm.items,2,"ling") : 表示 把vm.items 這個數(shù)組的下標(biāo)為2 的元素,改為"ling"

Vue.set(vm.person,"age","26")

Vue.set()向響應(yīng)式對象中添加一個屬性,并確保這個新屬性同樣是響應(yīng)式的,且觸發(fā)視圖更新。它必須用于向響應(yīng)式對象上添加新屬性,因為 Vue 無法探測普通的新增屬性 (比如 this.myObject.newProperty = 'hi')

區(qū)別在于Vue.set()是將set函數(shù)綁定在Vue構(gòu)造函數(shù)上,this.$set()是將set函數(shù)綁定在Vue原型上。

Vue.set數(shù)組實現(xiàn)的原理:其實Vue.set()對于數(shù)組的處理其實就是調(diào)用了splice方法

25. 虛擬 DOM 有什么優(yōu)點和缺、點

26. vue項目實現(xiàn)路由按需加載

27. 為什么 vue 不建議在 action 中修改 state 而是在 mutation 中修改

28. .vue是怎么渲染到頁面上的(源碼分析)

29. vue項目中實現(xiàn)圖片懶加載

30. vue3的新特性有了解過嗎

31. vue項目優(yōu)化

32. 為什么Vue3.0使用Proxy實現(xiàn)數(shù)據(jù)監(jiān)聽

33.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容