2.VUE組件data為什么必須是函數(shù)
答:Vue組件可能存在多個(gè)實(shí)例,如果使用對象形式定義data,則會(huì)導(dǎo)致它們共用一個(gè)data對象,那么狀態(tài)變更將會(huì)影響所有組件實(shí)例,這是不合理的。
采用函數(shù)形式定義,在initData時(shí)會(huì)將其作為工廠函數(shù)返回全新的data對象,有效規(guī)避多實(shí)例之間狀態(tài)污染問題。
而在Vue根實(shí)例創(chuàng)建過程中則不存在該限制,也是因?yàn)楦鶎?shí)例只能有一個(gè),不需要擔(dān)心這種情況。
3.Vue中key的作用和工作原理
- key的作用主要是為了高效的更新虛擬DOM,其原理是vue在patch過程中通過key可以精準(zhǔn)判斷兩個(gè)節(jié)點(diǎn)是否是同一個(gè),從而避免頻繁更新不同元素,使得整個(gè)patch過程更加高效,減少DOM操作量,提高性能。
- 另外,若不設(shè)置key還可能在列表更新時(shí)引發(fā)一些隱蔽的bug。
- vue中在使用相同標(biāo)簽名元素的過渡切換時(shí),也會(huì)使用到key屬性,其目的也是為了讓vue可以區(qū)分它們,否則vue只會(huì)替換其內(nèi)部屬性而不會(huì)觸發(fā)過渡效果。
4.你怎么理解vue中的diff算法?
- diff算法是虛擬DOM技術(shù)的必然產(chǎn)物:通過新舊虛擬DOM作對比(即diff),將變化的地方更新在真實(shí)DOM上;
另外,也需要diff高效的執(zhí)行對比過程,從而降低時(shí)間復(fù)雜度為0(N). - vue 2.x中為了降低Watcher粒度,每個(gè)組件必須有一個(gè)Watcher與之對應(yīng),只有引入diff才能精確找到發(fā)生變化的地方。
- vue中的diff執(zhí)行的時(shí)刻是組件實(shí)例執(zhí)行其更新函數(shù)時(shí),它會(huì)比對上一次渲染結(jié)果oldVnode和新的渲染結(jié)果newVnode,此過程成為patch.
- diff過程整體遵循深度優(yōu)先、同層比較的策略;兩個(gè)節(jié)點(diǎn)之間比較會(huì)更具它們是否擁有子節(jié)點(diǎn)或者文本節(jié)點(diǎn)做不同操作;
比較兩組子節(jié)點(diǎn)是算法的重點(diǎn),首先假設(shè)頭尾節(jié)點(diǎn)可能相同做4次比對嘗試;
如果沒有找到相同節(jié)點(diǎn)才按照通用方式遍歷查找,查找結(jié)束再按情況處理剩下的節(jié)點(diǎn);
借助key通??梢苑浅?zhǔn)確的找到相同節(jié)點(diǎn),因此整個(gè)patch過程非常高效。
5.談一談對vue組件化的理解
- 組件是獨(dú)立和可復(fù)用的代碼組織單元。組件系統(tǒng)是Vue核心特性之一,它使開發(fā)者使用小型、獨(dú)立和通常可復(fù)用的組件構(gòu)建大型項(xiàng)目;
- 組件化開發(fā)能大幅提高應(yīng)用開發(fā)效率、測試性、復(fù)用性等;
- 組件使用按分類有:頁面組件、業(yè)務(wù)組件、通用組件;
- vue的組件是基于配置的,我們通常編寫的組件是組件配置而非組件,框架后續(xù)會(huì)生成其構(gòu)造函數(shù),它們基于VueComponent,擴(kuò)展于Vue;
- vue中常見組件化技術(shù)有:屬性prop,自定義事件,插槽等,它們主要用于組件通信、擴(kuò)展等;
- 合理的劃分組件,有助于提升應(yīng)用性能;
- 組件應(yīng)該是高內(nèi)聚、低耦合的;
- 遵循單向數(shù)據(jù)流的原則。
6.談一談對vue設(shè)計(jì)原則的理解?
答:首先就是漸進(jìn)式JavaScript框架:與其它大型框架不同的是,Vue被設(shè)計(jì)為可以自底向上逐層應(yīng)用。
Vue的核心庫只關(guān)注視圖層,不僅易于上手,還便于與第三方庫或既有項(xiàng)目整合。
另一方面,當(dāng)與現(xiàn)代化的工具鏈以及各種支持類庫結(jié)合時(shí),Vue也完全能夠?yàn)閺?fù)雜的單頁應(yīng)用提供驅(qū)動(dòng)。
易用性
vue提供數(shù)據(jù)響應(yīng)式、聲明式模板語法和基于配置的組件系統(tǒng)等核心特性。
這些使我們只需要關(guān)注應(yīng)用的核心業(yè)務(wù)即可,只要會(huì)寫js,html和css就能輕松編寫vue應(yīng)用。
靈活性
漸進(jìn)式框架的最大優(yōu)點(diǎn)就是靈活性,如果應(yīng)用足夠小,我們可能僅需要vue核心特性即可完成功能;
隨著應(yīng)用規(guī)模不斷擴(kuò)大,我們才可能逐漸引入路由、狀態(tài)管理、vue-cli等庫和工具;
不管是應(yīng)用體積還是學(xué)習(xí)難度都是一個(gè)逐漸增加的平和曲線。
高效性
超快的虛擬DOM和diff算法使我們的應(yīng)用擁有最佳的性能表現(xiàn)。
追求高效的過程還在繼續(xù),vue3中將引入Proxy對數(shù)據(jù)響應(yīng)式改進(jìn)以及編譯器中對于靜態(tài)內(nèi)容編譯的改進(jìn)都會(huì)讓Vue更加高效。
7.對MVC、MVP和MVVM的理解
MVC
具備著View、Controller和Model
Model:負(fù)責(zé)保存應(yīng)用數(shù)據(jù),與后端數(shù)據(jù)進(jìn)行同步
Controller: 負(fù)責(zé)業(yè)務(wù)邏輯,根據(jù)用戶行為對Model數(shù)據(jù)進(jìn)行修改
View: 負(fù)責(zé)視圖展示,將Model中的數(shù)據(jù)可視化出來
MVP
MVP與MVC很接近,P指的是Presenter,presenter可以理解為一個(gè)中間人。
它負(fù)責(zé)著View和Model之間的數(shù)據(jù)流動(dòng),防止view和model之間直接交流。
MVVM(Model-View-ViewModel)
ViewModel通過實(shí)現(xiàn)一套數(shù)據(jù)響應(yīng)式機(jī)制自動(dòng)響應(yīng)Model中數(shù)據(jù)變化;
同時(shí)ViewModel會(huì)實(shí)現(xiàn)一套更新策略自動(dòng)將數(shù)據(jù)變化轉(zhuǎn)換為視圖更新;
通過事件監(jiān)聽響應(yīng)View中用戶交互修改Model中數(shù)據(jù)。
這樣再ViewModel中就減少了大量DOM操作代碼。
MVVM在保持View和Model松耦合的同時(shí),還減少了維護(hù)他們關(guān)系的代碼,使用戶專注于業(yè)務(wù)邏輯,兼顧開發(fā)效率和可維護(hù)性。
總結(jié)
這三者都是框架模式,它們設(shè)計(jì)的目標(biāo)都是為了解決Model和View的耦合問題。
MVC模式出現(xiàn)較早應(yīng)用在后端,在前端領(lǐng)域的走起也有應(yīng)用。
它們的優(yōu)點(diǎn)是分層清晰,缺點(diǎn)是數(shù)據(jù)流混亂,靈活性帶來的維護(hù)性問題。
MVP模式在是MVC的進(jìn)化形式,Presenter作為中間層負(fù)責(zé)MV通信,解決了兩者耦合問題,但P層過于臃腫會(huì)導(dǎo)致維護(hù)問題。
MVVM模式在前端領(lǐng)域有廣泛應(yīng)用,它不僅解決MV耦合問題,還同時(shí)解決了維護(hù)兩者映射關(guān)系的大量繁雜代碼和DOM操作代碼,在提高開發(fā)效率、可讀性同時(shí)還保持了優(yōu)越的性能表現(xiàn)。
8.你了解哪些Vue性能優(yōu)化方法
- 路由懶加載
const router = new VueRouter({
routes: [
{path: '/foo',component: ()=>import('./Foo.vue')}
]
})
- keep-alive緩存頁面
<template>
<div id="app">
<keep-alive>
<router-view />
</keep-alive>
</div>
</template>
- 使用v-show 復(fù)用DOM
- v-for 遍歷避免同時(shí)使用v-if
<template v-if="show">
<p v-for="v in list" :key="v.id">外層包一個(gè)template<p>
</template>
- 長列表性能優(yōu)化
如果列表是純粹的數(shù)據(jù)展示,不會(huì)有任何變化,就不需要做響應(yīng)化
export default {
data: () => ({
users: []
}),
async created() {
this.users = Object.freeze(獲取來的數(shù)據(jù))
}
}
如果是大數(shù)據(jù)長列表,可采用虛擬滾動(dòng),只渲染少部分區(qū)域的內(nèi)容
<recycle-scroller :items="items" :item-size="24">
<template v-slot="{item}">
<FetchItemView :item="item" @vote="voteItem(item)" />
</template>
</recycle-scroller>
- 事件的銷毀
Vue組件銷毀時(shí),會(huì)自動(dòng)解綁它的全部指令及事件監(jiān)聽器,但是僅限于組件本身的事件。
created() {
this.timer = setInterval(this.refresh, 2000)
},
beforeDestroy () {
clearInterval(this.timer)
}
- 圖片懶加載
對于圖片過多的頁面,為了加載頁面速度加速。所以很多時(shí)候我們需要將頁面內(nèi)未出現(xiàn)在可是區(qū)域內(nèi)的圖片先不做加載,等到滾動(dòng)到可視區(qū)域后再去加載
<img v-lazy="/static/img/1.png">
參考項(xiàng)目: vue-lozyload https://github.com/hilongjw/vue-lazyload
- 第三方插件按需引入
像element-ui這樣的第三方組件庫可以按需引入,避免體積較大。
import Vue from 'vue'
import {Button, Select} from 'element-ui'
Vue.use(Button)
Vue.use(Select)
- 無狀態(tài)的組件標(biāo)記為函數(shù)式組件
<template functional>
</template>
- 子組件分割
- 變量本地化
const base = this.base //不要頻繁引用this.base
- 服務(wù)端渲染 - SSR
9.你對Vue3.0的新特性有沒有了解?
- 更快
1.虛擬DOM重寫
2.優(yōu)化slots的生成
3.靜態(tài)樹提升
4.靜態(tài)屬性提升
5.基于Proxy的響應(yīng)式系統(tǒng) - 更小
1.通過搖樹優(yōu)化核心庫體積 - 更容易維護(hù)
1.TypeScript + 模塊化 - 更加友好
1.跨平臺(tái):編譯器核心和運(yùn)行時(shí)核心與平臺(tái)無關(guān),使得Vue更容易與任何平臺(tái)一起使用 - 更容易使用
1.改進(jìn)的TypeScript支持,編輯器能提供強(qiáng)有力的類型檢查和錯(cuò)誤及肩高 - 更好的調(diào)試支持
- 獨(dú)立的響應(yīng)化模塊
- Composition API