.什么是vue生命周期
Vue 實例從開始創(chuàng)建、初始化數(shù)據(jù)、編譯模板搁吓、掛載Dom→渲染原茅、更新→渲染、銷毀等一系列過程堕仔,稱之為 Vue 的生命周期擂橘,共八個階段。
作用: 生命周期中有多個事件鉤子摩骨,在控制整個 Vue實例
的過程時更容易形成好的邏輯通贞。
beforeCreate
: 完成實例初始化,this
指向被創(chuàng)建的實例恼五,data昌罩,computed,watch灾馒,mothods
方法 和 數(shù)據(jù)都不可以訪問茎用,數(shù)據(jù)觀測之前(data observer)
被調(diào)用。
created
: 實例創(chuàng)建完成睬罗,data轨功,computed,watch,methods
可被訪問,未掛載 Dom
十嘿,可對 data
進行操作,操作 Dom
需放到 nextTick
中。
beforeMount
: 有了el
圆米,找到對應(yīng)的 template
編譯成 render
函數(shù)
mounted
: 完成掛載 Dom
和 渲染卒暂,可對 Dom
進行獲取節(jié)點等操作,可發(fā)起后端請求拿到數(shù)據(jù)娄帖。
beforeUpdate
: 數(shù)據(jù)更新時調(diào)用也祠,發(fā)生在虛擬 Dom
重新渲染 和 打補丁之前之調(diào)用。
updated
: 組件 Dom
已完成更新近速,可執(zhí)行依賴的 Dom
操作诈嘿,不要操作數(shù)據(jù)會陷入死循環(huán)。
beforeDestroy
: 實例銷毀之前調(diào)用削葱,可進行優(yōu)化操作奖亚,如銷毀定時器,解除綁定事件析砸。
destroyed
: 組件已經(jīng)被銷毀昔字,事件監(jiān)聽器和子實例都會被移除銷毀。
首次頁面加載會觸發(fā)四個鉤子函數(shù): beforeCreate, created, beforeMount, mounted
且 DMO
渲染在 mounted
中就已經(jīng)完成了首繁。
可以使用 $on('hook:')
或 $once('hook:')
來簡化生命周期的注冊
.談?wù)?MVVM 模式
Model
: 代表數(shù)據(jù)模型作郭,也可以在 Model 中定義 數(shù)據(jù)修改 和 操作 的業(yè)務(wù)邏輯陨囊。
View
: 代表 UI 組件,它負(fù)責(zé)將 數(shù)據(jù)模型 轉(zhuǎn)化成 UI 展現(xiàn)出來夹攒。
ViewModel
: 監(jiān)聽模型數(shù)據(jù)的改變和控制視圖行為蜘醋、處理用戶交互,簡單理解就是一個同步 View 和 Model 的對象咏尝,連接 Model 和 View压语。
在 MVVM 架構(gòu)下,View 和 Model 之間并沒有直接的聯(lián)系状土,而是通過 ViewMode
進行交互无蜂,Model 和 ViewModel 之間的交互是雙向自動的, 因此 View 數(shù)據(jù)的變化會同步到 Model 中蒙谓,而 Model 數(shù)據(jù)的變化也會立即反應(yīng)到 View 上斥季。而開發(fā)者只需關(guān)注業(yè)務(wù)邏輯,不需要手動操作 DOM累驮,不需要關(guān)注數(shù)據(jù)狀態(tài)的同步問題酣倾,復(fù)雜的數(shù)據(jù)狀態(tài)維護完全由 MVVM 來統(tǒng)一管理。
MVVM 和 MVC區(qū)別谤专?
mvc
和 mvvm
其實區(qū)別并不大躁锡。都是一種設(shè)計思想。主要就是 mvc
中 Controller
演變成 mvvm
中的 viewModel
置侍。mvvm
主要解決了mvc
中大量的 DOM
操作使頁面渲染性能降低映之,加載速度變慢,影響用戶體驗蜡坊。和當(dāng) Model
頻繁發(fā)生變化杠输,開發(fā)者需要主動更新到 View
。
說下 Vue 實現(xiàn)數(shù)據(jù)雙向綁定的原理
Vue 實現(xiàn)數(shù)據(jù)雙向綁定主要是:采用 數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式
的方式秕衙,通過 Object.defineProperty()
來劫持各個屬性的 setter
蠢甲,getter
,在數(shù)據(jù)變動時發(fā)布消息給訂閱者据忘,觸發(fā)相應(yīng)監(jiān)聽回調(diào)鹦牛。當(dāng)把一個普通 Javascript
對象傳給 Vue 實例來作為它的 data
選項時,Vue 將遍歷它的屬性勇吊,用 Object.defineProperty()
將它們轉(zhuǎn)為 getter/setter
曼追。用戶看不到 getter/setter
,但是在內(nèi)部它們讓 Vue追蹤依賴汉规,在屬性被訪問和修改時通知變化拉鹃。
.請說一下 Vue 響應(yīng)式數(shù)據(jù)的原理是什么?
在 Vue 初始化數(shù)據(jù)時, 使用 Object.defineProperty
重新定義 data
中所有屬性,增加了數(shù)據(jù) 獲取(getter) / 設(shè)置(setter)
的攔截功能。在 獲取 / 設(shè)置
時可增加一些邏輯膏燕,這個邏輯交叫作 依賴收集
钥屈。當(dāng)頁面取到對應(yīng)屬性時會進行依賴收集, 如果屬性發(fā)生變化, 則會通知收集的依賴進行更新,而負(fù)責(zé)收集的就是 watcher
坝辫。
如負(fù)責(zé)渲染的 watcher
會在頁面渲染的時候?qū)?shù)據(jù)進行取值篷就,并把當(dāng)前 watcher
先存起來對應(yīng)到數(shù)據(jù)上,當(dāng)更新數(shù)據(jù)的時候告訴對應(yīng)的 watcher
去更新近忙, 從而實現(xiàn)了數(shù)據(jù)響應(yīng)式竭业。
data 一般分為兩大類: 對象類型 和 數(shù)組:
對象:
在 Vue 初始化的時候,會調(diào)用 initData
方法初始化 data
及舍,它會拿到當(dāng)前用戶傳入的數(shù)據(jù)未辆。判斷如果已經(jīng)被觀測過則不在觀測,如果沒有觀測過則利用 new Observer
創(chuàng)建一個實例用來觀測數(shù)據(jù)锯玛。如果數(shù)據(jù)是對象類型非數(shù)組的話會調(diào)用 this.walk(value)
方法把數(shù)據(jù)進行遍歷咐柜,在內(nèi)部使用 definReactive
方法重新定義( definReactive
是比較核心的方法: 定義響應(yīng)式 ),而重新定義采用的就是 Object.defineProperty
攘残。如當(dāng)前對象的值還是個對象拙友,會自動調(diào)用遞歸觀測。當(dāng)用戶取值的時候會調(diào)用 get
方法并收集當(dāng)前的 wacther
歼郭。在 set
方法里遗契,數(shù)據(jù)變化時會調(diào)用 notify
方法觸發(fā)數(shù)據(jù)對應(yīng)的依賴進行更新。
數(shù)組:
使用函數(shù)劫持的方式重寫了數(shù)組的方法病曾,并進行了原型鏈重寫牍蜂。使 data
中的數(shù)組指向了自己定義的數(shù)組原型方法。這樣的話泰涂,當(dāng)調(diào)用數(shù)組 API
時鲫竞,可以通知依賴更新。如果數(shù)組中包含著引用類型负敏,則會對數(shù)組中的引用類型進行再次監(jiān)控。
也就是當(dāng)創(chuàng)建了 Observer
觀測實例后秘蛇,如果數(shù)據(jù)是數(shù)組的話其做,判斷是否支持自己原型鏈,如果不支持則調(diào)用 protoAugment
方法使目標(biāo)指向 arrayMethods
方法赁还。arrayMethods
就是重寫的數(shù)組方法妖泄,包括 push
、pop
艘策、shift
蹈胡、unshift
、splice
、sort
和 reverse
共七個可以改變數(shù)組的方法罚渐,內(nèi)部采用函數(shù)劫持的方式却汉。在數(shù)組調(diào)用重寫的方法之后,還是會調(diào)用原數(shù)組方法去更新數(shù)組荷并。只不過重寫的方法會通知視圖更新合砂。如果使用 push
、unshift
和 splice
等方法新增數(shù)據(jù)源织,會調(diào)用 observeArray
方法對插入的數(shù)據(jù)再次進行觀測翩伪。
如果數(shù)組中有引用類型,則繼續(xù)調(diào)用 observeArray
方法循環(huán)遍歷每一項谈息,繼續(xù)深度觀測缘屹。前提是每一項必須是對象類型, 否則 observe
方法會直接 return
。
.為何 Vue 采用異步渲染?
如不采用異步更新, 則每次更新數(shù)據(jù)都會對當(dāng)前組件進行重新渲染, 因此為了性能考慮 Vue 在本輪數(shù)據(jù)更新結(jié)束后侠仇,再去異步更新視圖轻姿。
當(dāng)數(shù)據(jù)變化之后, 會調(diào)用 notify
方法去通知 watcher
進行數(shù)據(jù)更新。而 watcher
會調(diào)用 update
方法進行更新( 這里就是發(fā)布訂閱模式 )傅瞻。更新時并不是讓 wathcer
立即執(zhí)行踢代,而是放在一個 queueWatcher
隊列里進行過濾,相同的 watcher
只存一個嗅骄。最后在調(diào)用 nextTick
方法通過 flushSchedulerQueue
異步清空 watcher
隊列胳挎。
.nextTick 實現(xiàn)原理?
nextTick
方法主要是使用了 宏任務(wù) 和 微任務(wù) 定義了一個異步方法。多次調(diào)用 nextTick
會將方法存入隊列中溺森,通過這個異步方法清空當(dāng)前隊列慕爬。所以 nextTick
方法就是異步方法。
默認(rèn)在內(nèi)部調(diào)用 nextTick
時會傳入 flushSchedulerQueue
方法, 存在一個數(shù)組里并讓它執(zhí)行屏积。用戶有時也會調(diào)用 nextTick
医窿,調(diào)用時把用戶傳過來的 cb
也放在數(shù)組里,都是同一個數(shù)組 callbacks
炊林。多次調(diào)用 nextTick
只會執(zhí)行一次, 等到代碼都執(zhí)行完畢后姥卢,會調(diào)用 timerFunc
這個異步方法依次進行判斷所支持的類型:
如支持
Promise
則把timerFunc
包裹在了Promise
中并把flushCallbacks
放在了then
中, 相當(dāng)于異步執(zhí)行了flushCallBacks
。flushCallBacks
函數(shù)作用就是讓傳過來的方法依次執(zhí)行渣聚。如不是
IE
独榴、支持Mutationobserve
并且是原生的Mutationobserve
。首先聲明一個變量并創(chuàng)建一個文本節(jié)點奕枝。接著創(chuàng)建Mutationobserve
實例并把flushCallBacks
傳入, 調(diào)用observe
方法去觀測每一個節(jié)點棺榔。如果節(jié)點變化會異步執(zhí)行flushCallBacks
方法。如果支持
setImmediate
, 則調(diào)用setImmediate
傳入flushCallBacks
異步執(zhí)行隘道。以上都不支持就只能調(diào)用
setTimeout
傳入flushCallBacks
症歇。
作用:$nextTick
是在下次 DOM
更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)郎笆,在修改數(shù)據(jù)之后使用 $nextTick
,則可以在回調(diào)中獲取更新后的 DOM
忘晤。
.請說一下 Vue 中 Computed 和 watch ?
默認(rèn) computed
和 watch
內(nèi)部都是用一個 watcher
實現(xiàn)的 宛蚓。
computed
有緩存功能, 不會先執(zhí)行,只有當(dāng)依賴的屬性發(fā)生變化才會通知視圖跟新德频。
watcher
沒有緩存苍息,默認(rèn)會先執(zhí)行,只要監(jiān)聽的屬性發(fā)生變化就會更新視圖壹置。
computed
調(diào)用 initComputed
方法初始化計算屬性時竞思,會獲取到用戶定義的方法,并創(chuàng)建一個 watcher
把用戶定義傳進去钞护, 這個 watcher
有個標(biāo)識: lazy = true
盖喷,默認(rèn)不會執(zhí)行用戶定義的函數(shù)。還有個標(biāo)識 dirty = true
默認(rèn)去求值 难咕。watcher
內(nèi)部調(diào)用 defineComputed
方法將計算屬性定義在實例上课梳,其底層也是用的 Object.defineProperty
。并且傳入了 createComputedGetter
方法定義一個計算屬性余佃。在用戶取值時暮刃,調(diào)用的是 createComputedGetter
返回函數(shù) computedGetter
。判斷當(dāng)前的 watcher.dirty
是否為 true
爆土。如果為 true
則調(diào)用 watcher.evaluate
方法求值椭懊。在求值時是調(diào)用的 this.get()
方法。其實 this.get()
就是用戶傳入的方法步势,執(zhí)行時會把方法里的屬性依次取值氧猬。而在取值前調(diào)用了 pushTarget
方法將 watcher
放在了全局上,當(dāng)取值時會進行依賴收集坏瘩,把當(dāng)前的計算屬性的 watcher
收集起來盅抚。等數(shù)據(jù)變化則通知 watcher
重新執(zhí)行,也就是進入到了 update
方法中倔矾。update
并沒有直接讓 watcher
執(zhí)行妄均,而是將 dirty = true
。這樣的好處就是哪自,如果 dirty = true
丰包,就進行求值,否則就返回上次計算后的值提陶,從而實現(xiàn)了緩存的機制烫沙。
watch
調(diào)用 initWatch
方法初始化 watch
的時候匹层,內(nèi)部傳入用戶定義的方法調(diào)用了 createWatcher
方法隙笆。在 createWatcher
方法中比較核心的就是 $watch
方法锌蓄,內(nèi)部調(diào)用了 new Watcher
并傳入了 expOrFn
和 回調(diào)函數(shù)。expOrFn
如果是個字符串的話, 會包裝成一個函數(shù)并返回這個字符串撑柔。這時 lazy = false
了, 則直接調(diào)用了 this.get()
方法取屬性的值瘸爽。同 computed
在取值前也執(zhí)行 pushTarget
方法將 watcher
放在了全局上, 當(dāng)用戶取值時就收集了 watcher
。 因此當(dāng)屬性值發(fā)生改變時, watcher
就會更新铅忿。
如果監(jiān)聽的屬性值是個對象剪决,則取對象里的值就不會更新了,因為默認(rèn)只能對屬性進行依賴收集檀训,不能對屬性值是對象的進行依賴收集柑潦。想要不管屬性值是否是對象都能求值進行收集依賴,可設(shè)置 deep = true
峻凫。如設(shè)置了deep = true
渗鬼,則會調(diào)用 traverse
方法進行遞歸遍歷。
.Vue 組件中 data 為什么必須是一個函數(shù)荧琼?
因為 js 本身的特性帶來的譬胎,同一個組件被復(fù)用多次,會創(chuàng)建多個實例命锄。這些實例是同一個構(gòu)造函數(shù)堰乔。如果 data
是一個對象的話,那么所有組件都共享了同一個對象脐恩。為了保證組件中數(shù)據(jù)的獨立性要求每個組件必須通過 data
函數(shù)返回一個對象作為組件的狀態(tài)镐侯。
Vue 通過 extend
創(chuàng)建子類之后,會調(diào)用 mergeOptions
方法合并父類和子類的選項被盈,選中就包括 data
析孽。在循環(huán)完父類和子類之后調(diào)用 mergeField
函數(shù)的中的 strat
方法去合并 data
,如果 data
不是函數(shù)而是個對象只怎,則會報錯提示 data
應(yīng)該是個函數(shù)袜瞬。
.Vue 中事件綁定原理
Vue 中事件綁定分為兩種:
- 原生事件綁定: 采用的是
addEventListener
實現(xiàn) - 組件事件綁定: 采用的是
$on
方法實現(xiàn)
以 click
事件為例,普通 Dom
元素綁定事件是 @click
身堡,編譯出來是 on
和 click
事件邓尤,組件綁定事件是 @click
組件自定義事件 和 @click.native
原生事件兩種,編譯出來分別是 on
和 click
事件贴谎, nativeOn
和 click
事件汞扎。組件的 nativeOn
等價于普通元素的 on
,而組件的 on
單獨處理擅这。
渲染頁面時澈魄,普通 Dom
會調(diào)用 updateDOMListeners
方法,內(nèi)部先把 data.on
方法拿出來仲翎,然后調(diào)用 updateListeners
方法來添加一個監(jiān)聽事件痹扇,同時會傳入一個 add$1
方法铛漓。內(nèi)部調(diào)用 addEventListener
方法直接把事件綁定到元素上。
而組件會調(diào)用 updateComponentListeners
方法鲫构。內(nèi)部也是調(diào)用 updateListeners
方法但傳入的是 add
方法浓恶。這里的 add
方法與普通元素的 Dom
的 add$1
方法略有不同,采用的是自己定義的發(fā)布訂閱模式 $on
方法结笨,解析的是 on
方法包晰,組件內(nèi)部通過 $emit
方法觸發(fā)的。還有 click.native
方法是直接把事件綁在了最外層元素上炕吸,用的也是 updateListeners
方法傳入 add$1
方法伐憾。
.v-model 的實現(xiàn)原理是什么?
通俗講 v-model
可以看成是 value + input
的語法糖赫模。
組件的 v-model
也確實是這樣 塞耕。在組件初始化的時候, 如果檢測到有 model
屬性,就會調(diào)用 transformModel
方法轉(zhuǎn)化 model
。如果沒有 prop
屬性和 event
屬性, 則默認(rèn)會給組件 prop
為 value
屬性, 給 event
為 input
事件 嘴瓤。把 prop
的屬性賦給了 data.attrs
并把值也給了它扫外,即 data.attrs.value = '我們所賦的值'
。會給 on
綁定 input
事件廓脆,對應(yīng)的就是 callback
筛谚。
如果在組件內(nèi)自定義 model
的 prop
和 event
, 這樣的話組件初始化的時候, 接受 屬性
和 事件
時不再是 value
和 input
了, 而是我們自定義的 屬性
和 事件
。
如果是普通的標(biāo)簽, 則在運行時會自動判斷標(biāo)簽的類型, 生成不同的屬性 domProp
和 事件 on
停忿。還增加了指令 directive
, 針對輸入框的輸入法加上了一些邏輯并做了校驗和處理驾讲。
. Vue中的 v-show 和 v-if 是做什么用的, 兩者有什么區(qū)別席赂?
v-if
:會在 with
方法里進行判斷吮铭,如果條件為 true
則創(chuàng)建相應(yīng)的虛擬節(jié)點,否則就創(chuàng)建一個空的虛擬節(jié)點也就是不會渲染 DOM
颅停。
v-show
: 會在 with
方法里創(chuàng)建了一個指令就 v-show
谓晌,在運行的時候處理指令,添加了 style: display = none / originalDisplay
癞揉。
v-if
才是“真正的”條件渲染纸肉, 因為它會確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)谋讳N毀和重建。
v-if
也是惰性的喊熟, 如果在初次渲染時條件為假柏肪, 則什么也不做,一直到條件第一次變?yōu)檎鏁r芥牌, 才會渲染條件塊烦味。
相比之下, v-show
就簡單的多壁拉,不管初始條件是什么谬俄,元素總會被渲染岩遗, 并且只是簡單的基于 css
進行切換。
一般來說凤瘦,v-if
有更高的切換開銷,v-show
有更高的初始渲染開銷案铺。
因此蔬芥,如需要頻繁的切換則使用 v-show
較好,如在運行時條件不大可能改變則使用 v-if
較好控汉。
. v-if 和 v-for 為什么不能連用?
v-for
的優(yōu)先級會比 v-if
要高, 在 調(diào)用 with
方法編譯時會先進行循環(huán), 然后再去做 v-if
的條件判斷, 因此性能不高笔诵。
因此一般會把 v-if
提出來放在 v-for
外層, 或者想要連用把渲染數(shù)據(jù)放在計算屬性里進行過濾。
.Vue 中的 v-html 會導(dǎo)致哪些問題
v-html
其原理就是用 innerHtml
實現(xiàn)的的, 如果不能保證內(nèi)容是完全可以被依賴的, 則可能會導(dǎo)致 xxs 攻擊姑子。
在運行的時候, 調(diào)用 updateDOMProps
方法或解析配置的屬性, 如果判斷屬性是 innerHTML
的話, 會清除所有的子元素乎婿。
.Vue 中父子組件的調(diào)用順序
組件的調(diào)用都是先父后子,渲染完成的過程順序都是先子后父
組件的銷毀操作是先父后子街佑,銷毀完成的順序是先子后父
在頁面渲染的時候谢翎,先執(zhí)行父組件的 beforeCreate -> created -> befroreMount
,當(dāng)父組件實例化完成的時候會調(diào)用 rander
方法沐旨,判斷組件是不是有子組件森逮,如果有子組件則繼續(xù)渲染子組件以此類推。當(dāng)子組件實例化完成時候磁携,會把子組件的插入方法先存起來放到 instertedVNodeQueue
隊列里, 最后會調(diào)用 invokeIntertHook
方法把當(dāng)前的隊列依次執(zhí)行褒侧。
更新也是一樣,先父beforeUpdate -> 子beforeUpdate
再到 子 updated -> 父 updated
加載渲染過程
父beforeCreate-> 父created-> 父beforeMount-> 子beforeCreate-> 子created-> 子beforeMount- > 子mounted-> 父mounted
子組件更新過程
父beforeUpdate-> 子beforeUpdate-> 子updated-> 父updated
父組件更新過程
父beforeUpdate -> 父updated
銷毀過程
父beforeDestroy-> 子beforeDestroy-> 子destroyed-> 父destroyed
# Vue中父組件能監(jiān)聽到子組件的生命周期嗎
父組件通過@hook:
能夠監(jiān)聽到子組件的生命周期谊迄,舉個栗子:
// 這里是父組件
<template>
<child @hook:mounted="getChildMounted" />
</template>
<script>
method: {
getChildMounted () {
// 這里可以獲取到子組件mounted的信息
}
}
</script>
.Vue 中組件怎么通訊闷供?
父子通訊: 父 → 子
props
, 子 → 父$on / $emit
通過eventsMixin
方法中的$on
方法維護一個事件的數(shù)組统诺,然后將函數(shù)名傳入$emit
方法歪脏,循環(huán)遍歷出函數(shù)并執(zhí)行。獲得父子組件實例的方式:
$parent / $children
在初始化的時候調(diào)用initLifecycle
方法初始化$parent
和$children
放在實例上在父組件中提供數(shù)據(jù)供子組件/孫子組件注入進來:
Provide / Inject
粮呢。
通過initProvide
和initInjections
方法分別把provide
和reject
放在$options
上唾糯。在調(diào)用reject
的時候,調(diào)用resolveInject
方法遍歷鬼贱,查看父級是否有此屬性移怯,有則就直接return
并把它定義在自己的實例上。Ref
獲得實例的方式調(diào)用組件的屬性或方法
ref
被用來給元素或子組件注冊引用信息这难。引用信息將會注冊在父組件的 $refs 對象上舟误。
用在DOM
上就是DOM
實例,用在組件上就是組件實例姻乓。Event bus
實現(xiàn)跨組件通訊
實質(zhì)上還是基于$on
和$emit
嵌溢,因為每個實例都有$on
和$emit
并且事件的綁定和觸發(fā)必須在同一個實例眯牧,所以一般會專門定義一個實例去用于通信,如Vue.prototype.$bnts = new Vue
赖草。Vuex
狀態(tài)管理實現(xiàn)通訊$attrs
和$Listeners
實現(xiàn)數(shù)據(jù) 和 事件的傳遞学少,還有v-bind="$prop"
.為什么使用異步組件?
可使用異步的方式加載組件,減少打包體積,主要依賴 import()
語法秧骑,可實現(xiàn)文件的分割加載
components:{
testCpt: (resove) => import("../components/testCpt") 或
testCpt: r => require(['@/views/assetsInfo/assetsProofList'],r)
}
加載組件的時候版确,如果組件是個函數(shù)會調(diào)用 resolveAsyncComponent
方法, 并傳入組件定義的函數(shù) asyncFactory
, 并讓其馬上執(zhí)行。因為是異步的所以執(zhí)行后并不會馬上返回結(jié)果乎折。而返回的是一個 promise
绒疗,因此沒有返回值, 返回的是一個占位符。
加載完成后骂澄,會執(zhí)行 factory
函數(shù)并傳入了成功/失敗的回調(diào)吓蘑。在回調(diào) resolve
成功的回調(diào)時會調(diào)用 forceRander
方法, 內(nèi)部調(diào)用 $forceUpdate
強制刷新坟冲。之后 resolveAsyncComponent
判斷已經(jīng)執(zhí)行成功磨镶,就是去創(chuàng)建組件、初始化組件和渲染組件健提。
# Vue中的事件修飾符主要有哪些棋嘲?分別是什么作用
.stop
:阻止事件冒泡 .native
:綁定原生事件
.once
:事件只執(zhí)行一次
.self
:將事件綁定在自身身上,相當(dāng)于阻止事件冒泡
.prevent
:阻止默認(rèn)事件 .caption
:用于事件捕獲
# v-for 里面數(shù)據(jù)層次太多矩桂,數(shù)據(jù)不刷新怎么辦
運用 this.$forceUpdate()
迫使 Vue 實例重新渲染沸移。
注意它僅僅影響實例本身和插入插槽內(nèi)容的子組件,而不是所有子組件侄榴。
.說說對 keep-alive 的了解
keep-alive
是一個抽象組件雹锣,可實現(xiàn)組件緩存。當(dāng)組件切換時不會對當(dāng)前組件進行卸載癞蚕。
算法: LRU
→ 最近最久未使用法
常用的生命周期: activated
和 deactivated
聲明 keep-alive
時在函數(shù)里設(shè)置了幾個屬性: props
蕊爵,created
,destroyed
桦山,mounted
和rander
等;
-
props
: 調(diào)用keep-alive
組件可設(shè)置的屬性,共有三個屬性如下:
include: 想緩存的組件
exclude: 不想緩存的組件
max: 最多緩存多少個 -
created
: 創(chuàng)建一個緩存列表 -
destroyed
: 銷毀時清空所有緩存列表 -
mounted
: 會監(jiān)聽 include 和 exclude, 動態(tài)添加 或 移除緩存 -
rander
: 渲染時拿到第一個組件攒射,拿到第一個組件,判斷是不是在緩存里
.$route
和 $router
的區(qū)別是什么?
$router
為 VueRouter
實例恒水,是個全局路由對象会放,包含路由跳轉(zhuǎn)方法、鉤子函數(shù)等钉凌。
$route
是 路由信息對象 || 跳轉(zhuǎn)的路由對象咧最,每一個路由都會有一個route
對象,是一個局部對象,包含path矢沿,params滥搭,hash,query捣鲸,fullPath瑟匆,matched,name
等路由信息參數(shù)栽惶。
. Vue 路由的鉤子函數(shù)
首頁可以控制導(dǎo)航跳轉(zhuǎn)愁溜,beforeEach,afterEach等媒役,一般用于頁面title的修改。
一些需要登錄才能調(diào)整頁面的重定向功能宪迟。
beforeEach主要有3個參數(shù)to酣衷,from,next:
to:route即將進入的目標(biāo)路由對象次泽,
from:route當(dāng)前導(dǎo)航正要離開的路由
next:function一定要調(diào)用該方法resolve這個鉤子穿仪。執(zhí)行效果依賴next方法的調(diào)用參數(shù)∫饣纾可以控制網(wǎng)頁的跳轉(zhuǎn)啊片。
. vue-router有哪幾種路由守衛(wèi)?
- 全局守衛(wèi) ( vue-router 全局有三個守衛(wèi) )
router.beforeEach
全局前置守衛(wèi) 進入路由之前
router.beforeResolve
全局解析守衛(wèi)(2.5.0+) 在beforeRouteEnter調(diào)用之后調(diào)用
router.afterEach
全局后置鉤子 進入路由之后
// main.js 入口文件
import router from './router'; // 引入路由
router.beforeEach((to, from, next) => {
next();
});
router.beforeResolve((to, from, next) => {
next();
});
router.afterEach((to, from) => {
console.log('afterEach 全局后置鉤子');
});
- 路由獨享守衛(wèi)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// 參數(shù)用法什么的都一樣,調(diào)用順序在全局前置守衛(wèi)后面玖像,所以不會被全局守衛(wèi)覆蓋
}
}
]
})
- 路由組件內(nèi)的守衛(wèi)
beforeRouteEnter
進入路由前, 在路由獨享守衛(wèi)后調(diào)用 不能 獲取組件實例 this紫谷,組件實例還沒被創(chuàng)建
beforeRouteUpdate (2.2)
路由復(fù)用同一個組件時, 在當(dāng)前路由改變,但是該組件被復(fù)用時調(diào)用 可以訪問組件實例 this
beforeRouteLeave
離開當(dāng)前路由時, 導(dǎo)航離開該組件的對應(yīng)路由時調(diào)用捐寥,可以訪問組件實例 this
.hash 模式 和 history模式
hash:
在 url 中帶有 #笤昨,其原理是 onhashchange
事件。
可以在 window
對象上監(jiān)聽這個事件:
window.onhashchange = function(event){
...
}
history
: 沒有原 # , 其原理是 popstate 事件握恳,需要后臺配置支持瞒窒。
html5 中新增兩個操作歷史棧的API: pushState()
和 replaceState()
方法。
history.pushState(data[,title][,url]); // 向歷史記錄中追加一條記錄
history.replaceState(data[,title][,url]); // 替換當(dāng)前頁在歷史記錄中的信息乡洼。
這兩個方法也可以改變url崇裁,頁面也不會重新刷新,在當(dāng)前已有的 back束昵、forward拔稳、go 的基礎(chǔ)之上,它們提供了對歷史記錄進行修改的功能锹雏。只是當(dāng)它們執(zhí)行修改時壳炎,雖然改變了當(dāng)前的 URL,但瀏覽器不會立即向后端發(fā)送請求。
.Vuex 是什么? 怎么使用它? 哪種功能場景使用?
Vuex
是一個專為 Vue.js
應(yīng)用程序開發(fā)的狀態(tài)管理模式匿辩。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài)腰耙,并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。
Vuex
只能使用在 vue 上铲球,因為其高度依賴于 vue 的雙向綁定 和 插件系統(tǒng)挺庞。
調(diào)用了 Vue.mixin
,在所有組件的 beforeCreate
生命周期注入了設(shè)置 this.$store
這樣一個對象稼病。
場景有:單頁應(yīng)用中选侨,組件之間的狀態(tài)、音樂播放然走、登錄狀態(tài)援制、加入購物車
state
: Vuex 使用單一狀態(tài)樹,存放的數(shù)據(jù)狀態(tài)芍瑞,不可以直接修改里面的數(shù)據(jù)晨仑。
mutations
: 定義方法動態(tài)修改 Vuex 的 store
中的狀態(tài)或數(shù)據(jù)。
getters
: 類似 vue 的計算屬性拆檬,主要用來過濾一些數(shù)據(jù)洪己。
actions
: 可以理解為通過將 mutations
里面處理數(shù)據(jù)的方法變成可異步的方法,簡單的說就是異步操作數(shù)據(jù)竟贯。view
層通過 store.dispath
來分發(fā) action
答捕。
modules
: 項目特別復(fù)雜的時候,可以讓每一個模塊擁有自己的 state屑那、mutation拱镐、action、getters
持际,使得結(jié)構(gòu)非常清晰痢站,方便管理。
actions 和 mutations的區(qū)別
action
主要處理的是異步的操作选酗,mutation
必須同步執(zhí)行阵难,而 action
既可以處理同步,也可以處理異步的操作芒填。action
提交的是 mutation
呜叫,而不是直接變更狀態(tài)。
如果請求來的數(shù)據(jù)不是要被其他組件公用,僅僅在請求的組件內(nèi)使用,就不需要放入 vuex
的 state
里鸽素。
如果被其他地方復(fù)用亚再,請將請求放入 action
里方便復(fù)用莱预,并包裝成 promise
返回。
.assets 和 static的區(qū)別
相同點: assets
和 static
兩個都是存放靜態(tài)資源文件耽装。項目中所需要的資源文件圖片惕鼓,字體圖標(biāo)箱硕,樣式文件等都可以放在這兩個文件下拴竹。
不相同點:
assets
中存放的靜態(tài)資源文件在項目打包時,會將 assets
中放置的靜態(tài)資源文件進行打包上傳剧罩,所謂打包簡單點可以理解為壓縮體積栓拜,代碼格式化。而壓縮后的靜態(tài)資源文件最終也都會放置在static文件中跟著index.html
一同上傳至服務(wù)器惠昔。
static
中放置的靜態(tài)資源文件就不會要走打包壓縮格式化等流程幕与,而是直接進入打包好的目錄,直接上傳至服務(wù)器镇防。因為避免了壓縮直接進行上傳啦鸣,在打包時會提高一定的效率,但是 static
中的資源文件由于沒有進行壓縮等操作来氧,所以文件的體積也就相對于 assets
中打包后的文件提交較大點诫给。在服務(wù)器中就會占據(jù)更大的空間。
建議:將項目中 template
需要的樣式文件js文件等都可以放置在 assets
中饲漾,走打包這一流程蝙搔。減少體積缕溉。而項目中引入的第三方的資源文件如iconfoont.css等文件可以放置在 static
中考传,因為這些引入的第三方文件已經(jīng)經(jīng)過處理,我們不再需要處理证鸥,直接上傳僚楞。
Vue 中 key 的作用是什么?
需要使用 key 給每一個節(jié)點做唯一標(biāo)識枉层,可讓 diff 算法可以正確識別此節(jié)點泉褐,以更高效的更新虛擬 DOM。
新舊 children 中的節(jié)點只有順序是不同的時候鸟蜡,最佳的操作應(yīng)該是通過移動元素的位置來達到更新的目的
需要在新舊 children 的節(jié)點中保存映射關(guān)系膜赃,以便能夠在舊 children 的節(jié)點中找到可復(fù)用的節(jié)點。key也就是children中節(jié)點的唯一標(biāo)識
.用vnode描述一個DOM結(jié)構(gòu)
虛擬節(jié)點就是用一個對象描述真實的dom元素
會將 template
先轉(zhuǎn)換成 ast
樹, ast
通過代碼生成 codegen
轉(zhuǎn)成 rander
函數(shù), rander
函數(shù)內(nèi)部調(diào)用 $createElement
方法簡稱 _c
, 傳入 tag
(創(chuàng)建的元素), data
(元素的屬性), children
(子元素) . 會判斷 children
是不是一個字符串, 否則會做深度遞歸, 最后返回的結(jié)果就是一個對象,可描述出DOM
結(jié)構(gòu).
.簡述 Vue 中 diff 算法原理
- 先同級比較, 在比較子節(jié)點.
- 判斷出一方有子節(jié)點另一方?jīng)]有子節(jié)點的情況.
如果新的一方有子節(jié)點,老的沒有,則把子節(jié)點直接插入到老節(jié)點里即可.
如果老的一方有子節(jié)點,新的沒有,則把老的子節(jié)點直接刪除. - 判斷出都有子節(jié)點的情況, 遞歸遍歷子采用
雙指針
(頭/尾指針)的方式比對節(jié)點.
Vue.use 與 Vue.component 的區(qū)別
都用于注冊全局組件/插件的
Vue.component()
每次只能注冊一個組件揉忘,功能很單一跳座。
Vue.component('draggable', draggable)
Vue.use()
內(nèi)部調(diào)用的仍是 Vue.component()
去注冊全局組件/插件,但它可以做更多事情泣矛,比如多次調(diào)用 Vue.component() 一次性注冊多個組件疲眷,還可以調(diào)用Vue.directive()、Vue.mixins()您朽、Vue.prototype.xxx=xxx 等等狂丝,其第二個可選參數(shù)又可以傳遞一些數(shù)據(jù)
Vue.use({
install:function (Vue, options) {
// 接收傳遞的參數(shù): { name: 'My-Vue', age: 28 }
console.log(options.name, options.age)
Vue.directive('my-directive',{
inserted(el, binding, vnode) { }
})
Vue.mixin({
mounted() { }
})
Vue.component('draggable', draggable)
Vue.component('Tree', Tree)
}
},
{ name: 'My-Vue', age: 28 })
在main.js 文件里 動態(tài)注冊全局組件時, 或用到 require.context
require.context():
一個 Webpack 的API,獲取一個特定的上下文(創(chuàng)建自己的context),主要用來實現(xiàn)自動化導(dǎo)入模塊几颜。
它會遍歷文件夾中的指定文件倍试,然后自動化導(dǎo)入,而不需要每次都顯式使用 import / require 語句導(dǎo)入模塊菠剩!
在前端工程中易猫,如果需要一個文件夾引入很多模塊,則可以使用 require.context()
require.context(directory, useSubdirectories = false, regExp = /^\.\//)
directory
{String} 讀取目錄的路徑
useSubdirectories
{Boolean} 是否遞歸遍歷子目錄
regExp
{RegExp} 匹配文件的正則
既然 Vue 通過數(shù)據(jù)劫持可以精準(zhǔn)探測數(shù)據(jù)變化具壮,為什么還需要虛擬 DOM 進行 diff 檢測差異?
現(xiàn)代前端框架有兩種方式偵測變化,一種是 pull
一種是push
pull
: 其代表為 React
准颓,通常會用 setStateAPI
顯式更新,然后 React
會進行一層層的 Virtual Dom Diff
操作找出差異棺妓,然后 Patch
到 DOM
上攘已,React
從一開始就不知道到底是哪發(fā)生了變化,只是知道「有變化了」怜跑,然后再進行比較暴力的 Diff
操作查找「哪發(fā)生變化了」样勃,另外一個代表就是 Angular
的臟檢查操作。
push
: Vue
的響應(yīng)式系統(tǒng)則是 push
的代表,當(dāng) Vue
程序初始化的時候就會對數(shù)據(jù) data
進行依賴的收集性芬,一但數(shù)據(jù)發(fā)生變化峡眶,響應(yīng)式系統(tǒng)就會立刻得知,因此 Vue
是一開始就知道是「在哪發(fā)生變化了」植锉,但是這又會產(chǎn)生一個問題辫樱,如果你熟悉 Vue
的響應(yīng)式系統(tǒng)就知道,通常一個綁定一個數(shù)據(jù)就需要一個 Watcher
俊庇,一但我們的綁定細(xì)粒度過高就會產(chǎn)生大量的 Watcher
狮暑,這會帶來內(nèi)存以及依賴追蹤的開銷,而細(xì)粒度過低會無法精準(zhǔn)偵測變化辉饱,因此 Vue
的設(shè)計是選擇中等細(xì)粒度的方案,在組件級別進行 push
偵測的方式搬男,也就是那套響應(yīng)式系統(tǒng),通常我們會第一時間偵測到發(fā)生變化的組件彭沼,然后在組件內(nèi)部進行 Virtual Dom Diff
獲取更加具體的差異缔逛,而Virtual Dom Diff
則是 pull
操作,Vue
是 push+pull
結(jié)合的方式進行變化偵測的姓惑。
Vue 為什么沒有類似于 React 中 shouldComponentUpdate 的生命周期褐奴?
根本原因是 Vue
與 React
的變化偵測方式有所不同
React
是 pull
的方式偵測變化,當(dāng) React
知道發(fā)生變化后挺益,會使用 Virtual Dom Diff
進行差異檢測歉糜,但是很多組件實際上是肯定不會發(fā)生變化的,這個時候需要用 shouldComponentUpdate
進行手動操作來減少diff
望众,從而提高程序整體的性能匪补。
Vue
是 pull+push
的方式偵測變化的伞辛,在一開始就知道那個組件發(fā)生了變化,因此在 push
的階段并不需要手動控制 diff
夯缺,而組件內(nèi)部采用的 diff
方式實際上是可以引入類似于 shouldComponentUpdate
相關(guān)生命周期的蚤氏,但是通常合理大小的組件不會有過量的 diff
,手動優(yōu)化的價值有限踊兜,因此目前 Vue
并沒有考慮引入shouldComponentUpdate
這種手動優(yōu)化的生命周期竿滨。
.Vue 中常見的性能優(yōu)化
- 編碼優(yōu)化
(1). 不要將所有的數(shù)據(jù)放在data
里,data
中的數(shù)據(jù)都會增加gette
r和setter
,收收集對應(yīng)的watcher
(2). 在v-for
時給每項元素綁定事件必須使用時間代理
(3). SPA頁面采用keep-alive
緩存組件
(4). 拆分組件(提高復(fù)用性,增加代碼的可維護性,減少不必要的渲染)
(5).v-if
當(dāng)值為false
時內(nèi)部指令不執(zhí)行具有阻斷功能,很多情況下使用v-if
代替v-show
(6). 使用 key 保證唯一性
(7). 使用Object.freeze
凍結(jié)數(shù)據(jù),凍結(jié)后不再有getter
和setter
(8). 合理使用路由懶加載和異步組件
(9). 數(shù)據(jù)持久化問題如: 防抖捏境、節(jié)流 - Vue 加載性能優(yōu)化
(1). 第三方模塊按需導(dǎo)入(babel-plugin-component
)
(2). 滾動可視區(qū)域動態(tài)加載(vue-virtual-scroll-list
/ 'vue-virtual-scroller') -- 長列表優(yōu)化
(3). 圖片懶加載(vue-lazyload
) - 用戶體驗
(1).app-skeleton
骨架屏
(2).app-sheapp
殼 - SEO 優(yōu)化
(1). 預(yù)加載插件prerender-spa-plugin
(2). 服務(wù)端渲染 ssr - 打包優(yōu)化
(1). 使用 CDN 的方式加載第三方模塊
(2). 多線程打包
(3).splitChunk
抽離公共文件 - 緩存 壓縮
(1). 客戶端緩存和服務(wù)端緩存
(2). 服務(wù)端gzip壓縮
.什么是作用域插槽于游?
- 插槽: 創(chuàng)建組件虛擬節(jié)點時,會將組件兒子的虛擬節(jié)點先保存起來垫言。初始化組件時贰剥,通過插槽屬性將兒子進行分類。(作用域為父組件)
渲染組件時會拿對應(yīng)的slot
屬性的節(jié)點進行替換操作筷频。 - 作用域插槽: 在解析的時候不會作為組件的孩子節(jié)點蚌成。會解析成函數(shù),當(dāng)子組件渲染時凛捏,會調(diào)用此函數(shù)進行渲染担忧。(作用域為子組件)
普通插槽編譯時調(diào)用 createElement
方法創(chuàng)建組件,并把子節(jié)點生成虛擬 dom
做好標(biāo)識存起來坯癣。渲染時調(diào)用 randerSlot
方法循環(huán)匹配出對應(yīng)的虛擬節(jié)點在父組件替換當(dāng)前位置瓶盛。
而作用域插槽在編譯時會把子組件編譯成函數(shù),函數(shù)不調(diào)用就不會渲染坡锡。也就是說在初始化組件的時候并不會渲染子節(jié)點蓬网。渲染頁面時調(diào)用 randerSlot
方法執(zhí)行子節(jié)點的函數(shù)并把對應(yīng)的屬性傳過來鹉勒。當(dāng)節(jié)點渲染完成之后在組件內(nèi)部替換當(dāng)前位置。
.Vue與Angular以及React的區(qū)別禽额?
1.與AngularJS的區(qū)別
相同點:
- 都支持指令:內(nèi)置指令和自定義指令皮官。
- 都支持過濾器:內(nèi)置過濾器和自定義過濾器脯倒。
- 都支持雙向數(shù)據(jù)綁定捺氢。
- 都不支持低端瀏覽器。
不同點:
-
AngularJS
采用 TypeScript 開發(fā), 而 Vue 可以使用 javascript 也可以使用 TypeScript摄乒。 - 在性能上悠反,AngularJS依賴對數(shù)據(jù)做臟檢查残黑,所以Watcher越多越慢斋否。
Vue.js使用基于依賴追蹤的觀察并且使用異步隊列更新,所有的數(shù)據(jù)都是獨立觸發(fā)的疫诽。
對于龐大的應(yīng)用來 說旦委,這個優(yōu)化差異還是比較明顯的。 - AngularJS社區(qū)完善, Vue的學(xué)習(xí)成本較小
2.與React的區(qū)別
相同點:
- React采用特殊的JSX語法缨硝,Vue.js在組件開發(fā)中也推崇編寫.vue特殊文件格式,對文件內(nèi)容都有一些約定腺律,兩者都需要編譯后使用宜肉。
- 中心思想相同:一切都是組件,組件實例之間可以嵌套之斯。
- 都提供合理的鉤子函數(shù)遣铝,可以讓開發(fā)者定制化地去處理需求。
- 都不內(nèi)置AJAX酿炸,Route等功能核心包填硕,而是以插件的方式加載。
- 在組件開發(fā)中都支持mixins的特性扁眯。
不同點:
- vue 組件分為全局注冊和局部注冊壮莹,在 react 中都是通過 import 相應(yīng)組件,然后模版中引用姻檀;
- props 是可以動態(tài)變化的命满,子組件也實時更新,在 react 中官方建議props要像純函數(shù)那樣绣版,輸入輸出一致對應(yīng)胶台,而且不太建議通過 props 來更改視圖
- vue 多了指令系統(tǒng),讓模版可以實現(xiàn)更豐富的功能腋妙,而 React 只能使用JSX語法
- react 是整體的思路的就是函數(shù)式讯榕,所以推崇純組件愚屁,數(shù)據(jù)不可變,單向數(shù)據(jù)流送浊,當(dāng)然需要雙向的地方也可以做到丘跌,比如結(jié)合 redux-form,組件的橫向拆分一般是通過高階組件耸棒。而 vue 是數(shù)據(jù)可變的报辱,雙向綁定碍现,聲明式的寫法,vue組件的橫向拆分很多情況下用 mixin爽篷。
- Vue增加的語法糖computed和watch辩棒,而在React中需要自己寫一套邏輯來實現(xiàn)一睁。
高精度全局權(quán)限處理
權(quán)限控制由前端處理時佃却,通常使用 v-if / v-show 控制元素對不同權(quán)限的響應(yīng)效果。這種情況下复凳,就會導(dǎo)致很多不必要的重復(fù)代碼,不容易維護对途,因此可以造一個小車輪实檀,掛在全局上對權(quán)限進行處理按声。
// 注冊全局自定義指令,對底層原生DOM操作
Vue.directive('permission', {
// inserted → 元素插入的時候
inserted(el, binding){
// 獲取到 v-permission 的值
const { value } = binding
if(value) {
// 根據(jù)配置的權(quán)限须床,去當(dāng)前用戶的角色權(quán)限中校驗
const hasPermission = checkPermission(value)
if(!hasPermission){
// 沒有權(quán)限豺旬,則移除DOM元素
el.parentNode && el.parentNode.removeChild(el)
}
} else{
throw new Error(`need key! Like v-permission="['admin','editor']"`)
}
}
})
// --> 在組件中使用 v-permission
<button v-permission="['admin']">權(quán)限1</button>
<button v-permission="['admin', 'editor']">權(quán)限2</button>
.對于 vue3.0 特性你有什么了解的嗎柒凉?
(1). 監(jiān)測機制的改變
3.0 基于代理 Proxy 的 observer 實現(xiàn)扛拨,提供全語言覆蓋的反應(yīng)性跟蹤。替代了Vue 2采用 defineProperty去定義get 和 set, 意味著徹底放棄了兼容IE, 這也取消除了 Vue 2 當(dāng)中基于 Object.defineProperty 的實現(xiàn)所存在的很多限制:
=>只能監(jiān)測屬性求泰,不能監(jiān)測對象:
=>檢測屬性的添加和刪除计盒;
=>檢測數(shù)組索引和長度的變更北启;
=>支持 Map、Set场钉、WeakMap 和 WeakSet懈涛。
新的 observer 還提供了以下特性:
用于創(chuàng)建 observable 的公開 API
。這為中小規(guī)模場景提供了簡單輕量級的跨組件狀態(tài)管理解決方案宇植。
默認(rèn)采用惰性觀察
指郁。在 2.x 中,不管反應(yīng)式數(shù)據(jù)有多大晨横,都會在啟動時被觀察到箫柳。如果數(shù)據(jù)集很大,這可能會在應(yīng)用啟動時帶來明顯的開銷库糠。在 3.x 中瞬欧,只觀察用于渲染應(yīng)用程序最初可見部分的數(shù)據(jù)罢防。
更精確的變更通知
。在 2.x 中野建,通過 Vue.set 強制添加新屬性將導(dǎo)致依賴于該對象的 watcher 收到變更通知恬叹。在 3.x 中绽昼,只有依賴于特定屬性的 watcher 才會收到通知。
不可變的 observable
:我們可以創(chuàng)建值的“不可變”版本(即使是嵌套屬性)目溉,除非系統(tǒng)在內(nèi)部暫時將其“解禁”菱农。這個機制可用于凍結(jié) prop 傳遞或 Vuex 狀態(tài)樹以外的變化大莫。
更好的調(diào)試功能
:我們可以使用新的 renderTracked 和 renderTriggered 鉤子精確地跟蹤組件在什么時候以及為什么重新渲染。
(2). 模板
模板方面沒有大的變更烙丛,只改了作用域插槽羔味,2.x 的機制導(dǎo)致作用域插槽變了赋元,父組件會重新渲染,而 3.0 把作用域插槽改成了函數(shù)的方式媚值,這樣只會影響子組件的重新渲染护糖,提升了渲染的性能嫡良。
同時,對于 render 函數(shù)的方面坷牛,vue3.0 也進行一系列更改來方便習(xí)慣直接使用 api 來生成 vdom 很澄。
(3). 對象式的組件聲明方式
vue2.x
中的組件是通過聲明的方式傳入一系列 option甩苛,和 TypeScript 的結(jié)合需要通過一些裝飾器的方式來做,雖然能實現(xiàn)功能捐迫,但是比較麻煩施戴。
vue3.0
修改了組件的聲明方式萌丈,改成了類式的寫法,這樣使得和 TypeScript 的結(jié)合變得很容易肪笋。
此外藤乙,vue 的源碼也改用了 TypeScript 來寫。其實當(dāng)代碼的功能復(fù)雜之后而姐,必須有一個靜態(tài)類型系統(tǒng)來做一些輔助管理』溃現(xiàn)在 vue3.0 也全面改用 TypeScript 來重寫了褐缠,更是使得對外暴露的 api 更容易結(jié)合 TypeScript。靜態(tài)類型系統(tǒng)對于復(fù)雜代碼的維護確實很有必要公般。
(4). 其它方面的更改
支持自定義渲染器器躏,從而使得 weex 可以通過自定義渲染器的方式來擴展登失,而不是直接 fork 源碼來改的方式。
支持 Fragment(多個根節(jié)點)和 Protal(在 dom 其他部分渲染組建內(nèi)容)組件状婶,針對一些特殊的場景做了處理馅巷。
基于 treeshaking 優(yōu)化钓猬,提供了更多的內(nèi)置功能。
.Vue等單頁面應(yīng)用(spa)及其優(yōu)缺點
優(yōu)點
: Vue的目標(biāo)是通過盡可能簡單的 API實現(xiàn)響應(yīng)的數(shù)據(jù)綁定和組合的視圖組件账月,核心是一個響應(yīng)的數(shù)據(jù)綁定系統(tǒng)局齿。MVVM橄登、數(shù)據(jù)驅(qū)動讥此、組件化萄喳、輕量拌禾、簡潔湃窍、高效匪傍、快速役衡、模塊友好;即第一次就將所有的東西都加載完成榕莺,因此棵介,不會導(dǎo)致頁面卡頓邮辽。
缺點
: 不支持低版本的瀏覽器,最低只支持到IE9岩睁;不利于SEO的優(yōu)化(如果要支持SEO捕儒,建議通過服務(wù)端來進行渲染組件)邓夕;第一次加載首頁耗時相對長一些翎迁;不可以使用瀏覽器的導(dǎo)航按鈕需要自行實現(xiàn)前進、后退蒲拉。