1. v-if與v-show區別
v-if只有當條件是true才進行渲染,是真正的銷毀和重建。
v-show無論條件是否為true都會渲染,只不過是基于css display:none來進行切換。
一般來說,v-if切換開銷比較高,而v-show有比較高的初始渲染開銷
2. router-link與a有區別嗎
router-link其實還是轉換成了a標簽進行頁面跳轉。但是router-link利用了緩存機制,只渲染修改的部分。所有盡量使用router-link
3. vue-loader是什么?它的用途有哪些?
是基于webpack的一個的loader,解析和轉換 .vue 文件,提取出其中的邏輯代碼 script、樣式代碼 style、以及 HTML 模版 template,再分別把它們交給對應的 Loader 去處理,
selector–將.vue文件解析拆分成一個parts對象,其中分別包含style、script、template
style-compiler–解析style部分
template-compiler 解析template部分
babel-loader-- 解析script部分,并轉換為瀏覽器能識別的普通js
4. 計算屬性和watch的區別
計算屬性自動監聽依賴值得變化,從而動態返回內容。watch是一個過程,在監聽的值改變后,可以觸發一個回調,并做一些事情。
一般來說,如果只是需要動態值,用計算屬性;如果需要監聽值的變化后執行邏輯,用watch。
另外:
計算屬性是一個對象的時候,會有get和set兩個屬性。
計算屬性跟方法相比,計算屬性會有緩存,方法沒有;計算屬性不能接受參數,方法可以。
5. watch中的deep:true 是如何實現的?為什么computed沒有deep:true
如果用戶要監聽的是個對象,內層的對象就不會被依賴收集,這時候有一個deep屬性,要想讓收集到內層的對象,就需要將deep設置成true,這時候就會執行traverse這個方法,這個方法里就是做了個數組遞歸,如果是數組的話,會根據數組的每一項索引取值,進行遞歸追加依賴,如果是對象會拿的key進行遍歷取值,進行遞歸追加依賴,traverse就是deep:true實現的核心。這樣就會把數組或者對象的沒一個屬性都進行依賴追加進行監聽,只有依賴發生變化就會通知視圖更新
因為computed是用在模板里的,在模板中的數據會調一個方法JSON.strginify(),放一個對象,默認會對這個對象里的所有屬性求值。
6. 為何vue采用異步渲染
如果不采用異步渲染,那么每次更新數據都會對當前組件進行渲染。為了性能考慮,vue會在本輪數據更新后,異步更新視圖。(一個組件,更新了很多的數據,每次都要渲染,那效率就太低了)
7. 為什么組件中的 data 必須是一個函數,然后 return 一個對象,而 new Vue 實例里,data 可以直接是一個對象?
因為組件會被拿來復用。JS里的對象是引用關系,作用域沒有隔離。這樣一來就會造成不同組件的data相互影響。而new Vue的實例是不會被復用的,因此也不存在引用對象的問題。
8. vue中key的作用
key 的作用主要是為了更高效的更新虛擬 DOM,提高性能。
舉例來說,a、b、c、d、e五個節點,如果更新后變成了a、b、c、z、d、e。如果沒有key的話,diff算法會挨個更新元素。給節點添加key后,相當于是給節點添加了唯一標識。diff算法可以正確的識別節點,找到位置插入新的節點。
9. nextTick
作用:在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,可以獲取更新后的 DOM。
應用場景:需要在視圖更新之后,基于新的視圖進行操作。
觸發時機:在同一事件循環中的數據變化后,DOM完成更新,立即執行Vue.nextTick()的回調。
Vue 在內部對異步隊列嘗試使用原生的 Promise.then
、MutationObserver
和 setImmediate
,如果執行環境不支持,則會采用 setTimeout(fn, 0)
代替。宏任務耗費的時間是大于微任務的,所以在瀏覽器支持的情況下,優先使用微任務。如果瀏覽器不支持微任務,使用宏任務。
10. keep-alive
11. vue的雙向綁定原理
分對象和數組
對象的話,利用Object.defineProperty()來重新定義屬性,當屬性發生變化時,就會通知相關依賴進行更新操作。
數組的話,使用函數劫持的方法,重寫了數組的方法
Vue將data中的數組進行了原型鏈重寫,指向了自己定義的數組原型方法。這樣調用數組api(7種會改變數組的方法)時,就會通知依賴更新。如果數組中包含引用類型,則會對引用類型再進行監控。
vue3
vue.js 是采用數據劫持結合發布者-訂閱者模式的方式,通過new Proxy()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
Vue 3.0與Vue 2.0的區別僅是數據劫持的方式由Object.defineProperty更改為Proxy代理,其他代碼不變。
12. v-model是如何實現的
13. 單向數據流
vue 組件間傳遞數據是單向的,即數據總是由父組件傳遞到子組件,子組件在其內部可以有自己維護的數據,但它無權修改父組件傳遞給它的數據,當開發者嘗試這樣做的時候,vue 將會報錯。這樣做是為了組件間更好的解耦,在開發中可能有多個子組件依賴于父組件的某個數據,假如子組件可以修改父組件數據的話,一個子組件變化會引發所有依賴這個數據的子組件發生變化,所以 vue 不推薦子組件修改父組件的數據,直接修改 props 會拋出警告。
14. 組件通信
(1)props
一般屬性,父傳子
函數屬性,子傳父
父子通信比較常用的是,父傳子用props,子傳父用$emit(方法, 參數)
(2)事件總線,通過一個空的vue實例作為事件總線,用來觸發和監聽事件。$on
與$emit
可以實現任意組件間通信
(3)vuex
狀態管理。最常用,最方便。可以實現任意關系組件的通信。
(4)$parent
,$children
與ref
ref如果在子組件上,就指向子組件實例
15. vuex管理狀態的機制
vuex用來管理共享狀態
state是共享狀態的集合,getters通過操作state獲得派生狀態,mutations是操作state數據的方法集合,actions讓mutations中的方法能夠在異步操作中起作用
16. vue實例的生命周期
在beforeCreate 鉤子函數調用的時候,是獲取不到props 或者data 中的數據的,因為這些數據的初始化都在initState 中。
然后會執行created 鉤子函數,在這一步的時候已經可以訪問到之前不能訪問到的數據,但是這時候組件還沒被掛載,所以是看不到的。
接下來會先執行beforeMount 鉤子函數,開始創建VDOM,最后執行mounted 鉤子,并將VDOM 渲染為真實DOM 并且渲染數據。組件中如果有子組件的話,會遞歸掛載子組件,只有當所有子組件全部掛載完畢,才會執行根組件的掛載鉤子。
再接下來是數據更新時會調用的鉤子函數beforeUpdate 和updated,這兩個鉤子函數沒什么好說的,就是分別在數據更新前和更新后會調用。
另外還有keep-alive 獨有的生命周期,分別為activated 和deactivated 。用keep-alive 包裹的組件在切換時不會進行銷毀,而是緩存到內存中并執行deactivated 鉤子函數,命中緩存渲染后會執行actived 鉤子函數。
最后就是銷毀組件的鉤子函數beforeDestroy 和destroyed。前者適合移除事件、定時器等等,否則可能會引起內存泄露的問題。然后進行一系列的銷毀操作,如果有子組件的話,也會遞歸銷毀子組件,所有子組件都銷毀完畢后才會執行根組件的destroyed 鉤子函數。
17. 何時需要使用beforeDestroy
當前頁面中使用了$on方法,那就需要在組件銷毀前解綁
清除自己定義的定時器
解除事件的綁定scroll, mousemove等
18. Vue模板編譯原理
19. 虛擬dom
20. diff算法
21. $.set
我們在data中定義一個對象后,如果給對象增加新的屬性。則這個新增加的屬性不是響應式的。當數據發生變化,并不會顯示到視圖。這是因為新添加的屬性沒有被Object.defineProperty劫持,導致視圖不會同步更新。解決辦法是使用this.$set(obj, 'name', 'jack')
對于數組,直接通過索引設置元素,例如arr[] = 2
修改數組長度,例如arr.length = 6
vue同樣不能監測到數據變化