目錄
2.v-if、v-show區(qū)別
3.vue-router 有哪些模式? 區(qū)別是什么? 具體是怎么實現(xiàn)的
14.diff算法
自定義指令(v-check、 v-focus)的方法有哪些?它有哪些鉤子函數(shù)?
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ū)別
- hash路由在地址欄URL上有#,用 window.location.hash 讀取。而history路由沒有會好看一點
- 我們進(jìn)行回車刷新操作,hash路由會加載到地址欄對應(yīng)的頁面,而history路由一般就404報錯了(刷新是網(wǎng)絡(luò)請求,沒有后端準(zhǔn)備時會報錯)。
- 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 后回車,或者刷新(重啟)瀏覽器的時候。
- hash 模式下,僅 hash 符號之前的內(nèi)容會被包含在請求中,如 http://www.abc.com,因此對于后端來說,即使沒有做到對路由的全覆蓋,也不會返回 404 錯誤。
- 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>
- 結(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
}
大概流程
判斷目標(biāo)值是否為有效值,不是有效值直接停止
判斷是否為數(shù)組,并且key值是否為有效的key值
如果是數(shù)組,就選擇數(shù)組的長度和key值取較大值作為數(shù)組的新的length值,并且替換目標(biāo)值splice方法,重寫了,所以執(zhí)行splice,會雙向數(shù)據(jù)綁定判斷目標(biāo)值是否為響應(yīng)式的ob
如果是vue實例,直接不行
如果不是響應(yīng)式的數(shù)據(jù),就是普通的修改對象操作
如果是響應(yīng)式數(shù)據(jù),那就通過Object.defineProperty進(jìn)行數(shù)據(jù)劫持通知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
})
}
}
- nextTick接受一個回調(diào)函數(shù)時(當(dāng)不傳參數(shù)的時候,提供一個Promise化的調(diào)用),傳入的回調(diào)函數(shù)會在callbacks中存起來,根據(jù)一個狀態(tài)標(biāo)記 pending 來判斷當(dāng)前是否要執(zhí)行 timerFunc();
- timerFunc() 是根據(jù)當(dāng)前環(huán)境判斷使用哪種方式實現(xiàn),按照 Promise.then和 MutationObserver以及setImmediate的優(yōu)先級來判斷,支持哪個就用哪個,如果執(zhí)行環(huán)境不支持,會采用setTimeout(fn, 0)代替;
- 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方法