created跟mounted生命周期方法有什么區(qū)別
- created的時(shí)候dom未進(jìn)行渲染,不能做dom相關(guān)的操作
- mounted的時(shí)候dom已經(jīng)渲染完成了
vue的 nextTick是如何實(shí)現(xiàn)的
1、執(zhí)行時(shí)機(jī)會(huì)在dom更新完成之后調(diào)用
2、先把所有的回調(diào)任務(wù)都加到callbacks數(shù)組中,然后定義一個(gè)flushCallbacks方法遍歷數(shù)組執(zhí)行回調(diào)函數(shù),最后判斷瀏覽器支持Promise -> new MutationObserver(flushCallbacks) -> setImmediate -> setTimeout 找出一個(gè)方法來執(zhí)行flushCallbacks函數(shù),
3、MutationObserver是一個(gè)監(jiān)聽到DOM更新后,調(diào)用回調(diào)函數(shù)的API,主要目的是在當(dāng)前同步代碼執(zhí)行完畢之后,執(zhí)行我們傳入的回調(diào)函數(shù)
父子組件掛載生命周期順序
先執(zhí)行最內(nèi)層的生命周期,后執(zhí)行最外面的生命周期
vue2中數(shù)組和對(duì)象 數(shù)據(jù)觀察時(shí)有什么特殊處理
對(duì)象是遞歸遍歷每一個(gè)key加數(shù)據(jù)劫持, 數(shù)組是通過重寫其中會(huì)改變?cè)瓟?shù)組內(nèi)容的一些函數(shù),例如push pop splice等等操作函數(shù)
vue2和3中數(shù)據(jù)觀察的區(qū)別
- vue2用的是Object.defineProperty定義每一個(gè)key的get以及set方法,在get中收集依賴
- 在set中通知Watcher更新
- vue3則是通過系統(tǒng)自帶的Proxy做一個(gè)攔截,實(shí)現(xiàn)同樣的效果,也是定義get跟set方法
const dinner = ["test1", "test2"];
const handler = {
get(target, prop, receiver) {
// track(target, prop)
return Reflect.get(...arguments);
},
set(target, key, value, receiver) {
// trigger(target, key)
return Reflect.set(...arguments);
},
};
const proxy = new Proxy(dinner, handler);
console.log(proxy[0]);
proxy[1] = "test3";
console.log(proxy[1]);
vue兄弟節(jié)點(diǎn)通信
- eventbus
產(chǎn)生事件:
this.$root.$emit('change-color')
接受事件:
this.$root.$on('change-color', () => {
this.colored = !this.colored
})
import Vue from 'vue'
export default new Vue()
import bus from './eventBus'; //這里bus != this.$root,但是都可以用來傳遞事件兩者事件不通
虛擬dom解決了什么問題
- 首先是正常的一個(gè)真實(shí)dom擁有的屬性非常多,還擁有很多dom操作的方法
- 其次數(shù)據(jù)更新的時(shí)候如果整個(gè)畫面重新渲染會(huì)帶來很大的性能開銷,非常慢,而且很多沒變化的部分都屬于無用功,還不能保存數(shù)據(jù)更新前的狀態(tài)
- 用新數(shù)據(jù)生成的虛擬dom跟上次舊的虛擬dom做對(duì)比,只更新發(fā)生變化的部分
- diff算法也是消耗性能的,所以如果我們知道要修改那個(gè)dom,直接手動(dòng)操作應(yīng)該是最快的,這樣做是為了讓我們更關(guān)注數(shù)據(jù)的變化,而不需要關(guān)心dom操作
vue的diff和react的diff
- 相同點(diǎn):
都不做跨層比較,只做同層比較,如果某一節(jié)點(diǎn)不同就會(huì)銷毀當(dāng)前的,創(chuàng)建一個(gè)新的
- 不同點(diǎn):
Vue進(jìn)行diff算法的時(shí)候一邊比較,一邊用新的虛擬dom去更新真實(shí)dom
Vue認(rèn)定相同節(jié)點(diǎn),判斷key、標(biāo)簽、data都要相同
3.Vue對(duì)比是從兩端到中間做對(duì)比,兩兩進(jìn)行比較,每次對(duì)比完指針往中間移動(dòng)React是從左往右進(jìn)行對(duì)比,如果同樣把集合最后一個(gè)節(jié)點(diǎn)移動(dòng)到第一個(gè),react會(huì)把前面節(jié)點(diǎn)依次后移,vue會(huì)把最后一個(gè)節(jié)點(diǎn)放在最前面
通過key值查找新舊節(jié)點(diǎn)中相同可以復(fù)用的節(jié)點(diǎn),因此當(dāng)同類型節(jié)點(diǎn)內(nèi)容不同但是key前后之后可能導(dǎo)致更新失敗的問題
- 對(duì)于同樣的abcd -> dabc ,vue會(huì)直接把d拿到第一個(gè), react會(huì)把a(bǔ),b,c摞到最后一個(gè),d不動(dòng);(拿節(jié)點(diǎn)舊Index與當(dāng)前處理到的index進(jìn)行對(duì)比,小于的進(jìn)行移動(dòng),大于index不操作)
兩篇參考文章:
談?wù)凴eact中Diff算法的策略及實(shí)現(xiàn)
Vue跟react對(duì)比
兩者的模板渲染、兩者的虛擬 dom、diff 差異(vue2、vue3、react 16)、react fiber 能解決什么問題、vue2 的響應(yīng)式原理和 vue3 的響應(yīng)式原理;vue 關(guān)于 Proxy 與 Object.defineProperty 的區(qū)別;兩者的批量更新,還有路由差異、常用的優(yōu)化手段、怎么進(jìn)行數(shù)據(jù)通信、講點(diǎn)新鮮的內(nèi)容:新發(fā)布的 vue3 有什么特性、最后總結(jié),談?wù)剝烧叩娜缃竦纳鷳B(tài)
computed怎么實(shí)現(xiàn)的
computed引入其他computed的屬性是怎么實(shí)現(xiàn)的
watch怎么實(shí)現(xiàn)的
- 初始化了一個(gè)Watcher,讀取了一遍數(shù)據(jù),這個(gè)時(shí)候觀察者就會(huì)記錄自己依賴了哪些變量,變化的時(shí)候回調(diào)用回調(diào)函數(shù)
- 假如傳入deep,表示深度觀察,get的時(shí)候如果deep是true,就會(huì)讀一遍所有的屬性,調(diào)用get方法的時(shí)候就會(huì)將Watcher添加到每一個(gè)變量的dep中去
Vue.prototype.$watch = function (expOrFn,cb,options) {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
cb.call(vm, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
}
}
$on跟$emit原理
用vm._events[event] = [fn1,fn2],然后$emit去查找vm._events
有沒有這個(gè)事件,有就遍歷調(diào)用同時(shí)綁定this
handler.apply(context, args)
$off: vm._events[event] = null
$once: 調(diào)用完一次就調(diào)用$off關(guān)閉事件
Vue.directive自定義指令
1、用法
//定義
Vue.directive('color', {
// el 被綁定元素的元素
// obj 傳遞的參數(shù)
bind: function (el, obj) {
// el.style.color = 'blue'
el.style.color = obj.value
}
})
//使用
<div v-color="'red'">11111111111</div>
- 作用,比如可以用來自動(dòng)聚焦,定義按鈕防連點(diǎn)等
- 存儲(chǔ)如下:
this.options.directives ={
color: {bind: ?}
}
{
'v-focus':{
name : 'focus' , // 指令的名稱
value : '', // 指令的值
arg:'', // 指令的參數(shù)
modifiers:{}, // 指令的修飾符
def:{
inserted:fn
}
}
}
keep-alive
- 用法:
- <keep-alive>組件可接收三個(gè)屬性:
- include - 字符串或正則表達(dá)式。只有名稱匹配的組件會(huì)被緩存。
- exclude - 字符串或正則表達(dá)式。任何名稱匹配的組件都不會(huì)被緩存。
- max - 數(shù)字。最多可以緩存多少組件實(shí)例。
- 原理:實(shí)際上是把滿足規(guī)則的組件緩存下來
- 如果命中緩存就在移除之后放到最后一個(gè)
- 如果沒有命中緩存就將當(dāng)前vnode緩存下來
- 如果超過max就把第一個(gè)移除
- 為什么要?jiǎng)h除第一個(gè)緩存組件并且為什么命中緩存了還要調(diào)整組件key的順序?
LRU策略,最近最少使用,把最常用的放在最后,超過限制移除第一個(gè)
this.cache = Object.create(null)
this.cache = {
'key1':'組件1',
'key2':'組件2',
// ...
}
- 經(jīng)驗(yàn)總結(jié):
keep-alive包裹的組件只會(huì)執(zhí)行一次created、mounted,再次激活就是調(diào)用activated
總結(jié)用起來很麻煩,有很多緩存不刷新的坑,還不如用強(qiáng)緩存