Vue 知識點
原理篇
一、Vue 響應式原理
- Vue2 中,是通過 ES5 中的
definePropertyapi 來對對象的屬性進行 get 和 set 操作的攔截,在進行攔截操作時還創(chuàng)建了一個 watcher 用來跟蹤對應的 value 的變化,因為這種方式無法對數(shù)組進行攔截,所以在 vue 中,要實現(xiàn)數(shù)組的響應式,需要調(diào)用其內(nèi)置的set 的用法),defineProperty 是一個無法 polyfill 的api,所以 vue 不支持 IE8 以下的版本
- Vue3 使用ES6 的
Proxy內(nèi)置對象完全改了響應式的底層實現(xiàn),但原理都是類似地,(為對象屬性添加攔截器和偵聽器),Proxy 能更高效地對對象添加自定義操作,同時也支持了對數(shù)組的代理。不過也有問題,就是 Proxy 不支持對原始類型數(shù)據(jù)的代理,所以在 vue3 中,為實現(xiàn)原始類型數(shù)據(jù)的響應,對原始數(shù)據(jù)類型進行了對象化包裝。同樣地,Proxy 也是一個無法被 polyfill 的 api,所以 vue3 不支持 IE11 以下的版本
二、v-model的實現(xiàn)原理
v-model 是通過表單元素的 change/input 事件,然后在事件觸發(fā)時,發(fā)送一個 自定義的 update 事件,并將原始事件對象中的 value 當作參數(shù)發(fā)送出去,然后更新到 v-model 綁定的值上
應用(APP)篇
三、組件的生命周期
Vue 2
beforeCreated => created => beforeMount => mounted => beforeDestroy => destroyed
如果組件發(fā)生了更新,還會觸發(fā)以下生命周期鉤子
beforeUpdate => updated
如果使用了 keep-alive,則會額外增加兩個生命周期: actived, deactived
Vue 3
Vue 3 新增了組合式 API,不過 Vue 2 中的 Option API 也可以繼續(xù)使用,要使用組合式 API,需要使用 setup 方法或者 <script setup> 語法糖
在組合式 API 中,beforeCreated 和 created 直接整合到了 setup 方法,其他的采用了 on + 生命周期名稱形式的方法鉤子函數(shù),其中 destroy相關的鉤子都改成了 unmounted / beforeUnmount
選項式 API 生命周期
| Vue2.x | Vue3.x | Composition API |
|---|---|---|
| beforeCreate | -- (代表無變化) | setup |
| created | -- | setup |
| beforeMount | -- | onBeforeMount |
| mounted | -- | onMounted |
| beforeDestroy | beforeUnmount | onBeforeUnmount |
| destroyed | unmounted | onMounted |
同樣的,beforeUpdate 在 composition API 中需要使用 onBeforeUpdate, updated => onUpdated, activated => onActivated
四、組件間的通信
父子級組件
當子組件需要接收父組件中的數(shù)據(jù)時,可以通過 props 的方式傳遞
當父組件需要獲取子組件中的數(shù)據(jù)時,可以在子組件中發(fā)送一個自定義事件,然后將相關數(shù)據(jù)當作參數(shù)傳遞出去,在父組件中監(jiān)聽對應的事件并接收參數(shù)。另外一種方式就是給子組件添加一個 ref,然后在父組件中通過 this.$refs.[componentRefName]的方式獲取子組件的實例然后拿到子組件中的數(shù)據(jù)
同級組件
同級組件之間進行數(shù)據(jù)通信,通常可以使用以下幾種方式:
- 將數(shù)據(jù)交給共同的父級組件管理,子組件通過自定義事件將父組件傳遞數(shù)據(jù),而父組件通過 props 將數(shù)據(jù)傳給子組件,這種方式相對來說比較麻煩,有時可能需要層層上傳,甚至到根組件
- 在 Vue 2 中可以通過 new 一個 Vue 的實例來創(chuàng)建 eventBus,通過全局事件總線來傳遞數(shù)據(jù),不過這種方式在 vue 3 中被廢棄了
- 通過第三方 PubSub 工具(比如:emitter)創(chuàng)建自定義事件,通過事件參數(shù)的方式來實現(xiàn)同級組件之間的通信
- 使用 Vuex / redux 這種全局狀態(tài)管理工具也可以實現(xiàn)組件間的數(shù)據(jù)通信
- 還有種方式就是通過 mixin,但這種方式容易導致數(shù)據(jù)被污染,一般不建議使用
深層嵌套組件
父子級組件進行數(shù)據(jù)傳遞,通過 props 就可以實現(xiàn),也比較方便,但當一個組件需要向?qū)O子級組件或者更深層次的組件傳遞數(shù)據(jù)時,props 就顯得比較復雜了,每個子組件上都需要添加一個 props,這種方法十分不方便,所以 Vue 提供了 Provider/Inject來實現(xiàn)多級嵌套組件之間的數(shù)據(jù)傳遞。
在頂層組件中使用 Provider 定義需要傳遞下去的數(shù)據(jù),在嵌套層級組件中通過 Inject 來使用
需要注意的是,組件 Provider 中的數(shù)據(jù),只提供給其子孫級組件使用
五、對 Vue 進行擴展
在 vue 2 中,可以通過給 Vue 的原型加上自定義的方法來實現(xiàn)全局的方法,在組件實例中通過 this.customMethod 調(diào)用
Vue.prototype.customMethod
Vue 3 廢棄了修改 prototype 來對 vue 進行自定義擴展的操作。vue 3 為應用實例(通常命名為 app)添加了 config 對象屬性,在 config 屬性上,通過配置 globalProperties 來實現(xiàn)自定義擴展,調(diào)用的方法與 vue 2 中基本一致
六、API 篇
-
v-if與v-show的異同v-if 與 v-show 都是控制元素的顯示與隱藏,其中 v-if 是通過控制 DOM 節(jié)點的創(chuàng)建與銷毀來實現(xiàn)的,v-show 是通過控制 css 中的 display 屬性來實現(xiàn)的。
v-if 有更高的渲染開銷,v-show 有更高的初始化開銷,如果要頻繁控制 DOM 節(jié)點的話,需要使用 v-show,如果用在組件上,需要能觸發(fā)組件的生命周期,則需要使用 v-if,這時需要注意最好不要對組件進行頻繁的顯示與隱藏切換操作
另外,v-if 可以與 v-else-if, v-else 配合使用來進行條件渲染,不過綁定了這些指令的元素必須為同級的
-
v-if與v-forv-if 與 v-for 其實是可以在同一個元素上使用的,但是不管是官方還是實際項目中都不推薦這么使用,如果需要在 v-for 生成的列表元素使用條件渲染,建議將 v-for 放在一個 template 標簽上去使用,同理,也是建議將 v-if 放在 template 上去使用,也可以自定義一個包裹容器,只是 template 不會生成額外的 DOM 節(jié)點。
優(yōu)先級:在 vue 2.x 中,v-for 的優(yōu)先級要比 v-if 高,但在 vue 3中,v-if 的優(yōu)先級要比 v-for 高
-
key的作用在 vue 中,key 這個屬性最常見的用法就是與 v-for 一起使用,當然也可以獨立使用,key 的主要作用就是對組件或虛擬DOM節(jié)點添加唯一標識符,方便底層 diff 算法在節(jié)點或組件發(fā)生變化時能快速定位更新。如果不使用 key,Vue 會使用一種最大限度減少動態(tài)元素并且盡可能的嘗試就地修改/復用相同類型元素的算法。某些時候會導致 BUG,比如 v-for 渲染了 輸入類元素時,缺少 key 或使用 index 當作key時,當列表長度發(fā)生了非順序性變化時,就極易出 BUG。
-
watch與computedwatch 與 computed 在很多時候,用法都差不多,但也有差異,computed 主要是依賴項發(fā)生了變化時,它自身屬性跟著變化,但如果其依賴項沒有發(fā)生變化時,則其同樣不會發(fā)生變化,這種特性使其可以用來進行一定的性能優(yōu)化。watch 主要是當偵聽的數(shù)據(jù)發(fā)生變化時,去觸發(fā)其他的數(shù)據(jù)變化。
簡單來說,watch 主要用于需要根據(jù)數(shù)據(jù)變化來修改其他數(shù)據(jù)的操作,而computed更適用于依賴其他數(shù)據(jù)變化來修改自身的操作
另外,有較大開銷和異步操作時,watch 更合適
-
樣式綁定
Class綁定:vue 可以對元素的類名進行動態(tài)綁定,其值大概有以下幾種:
-
{ className: truthy | falsy }: 當綁定的值為對象時,該對象的屬性則會被編譯成元素的類目,而屬性對應的值應該為一個Boolean值,用于控制該屬性是否被編譯成類目 -
classNameString[]: 純 className 字符串組成的數(shù)組,數(shù)組中的所以元素都會被編譯成樣式類別 -
classNameString | classObject []: 對象語法與數(shù)組語法混用的模式
Style 綁定:
-
{ styleProperty: styleValue }: 當樣式綁定的值為對象時,對象的property則應該為具體樣式對應的屬性,value 則為樣式的值,注意寫法需要符合js對象的基本語法 -
styleObj[]: 當綁定的值為數(shù)組時,則數(shù)組中的每個元素應該為一個樣式對象的引用
-
-
組件
props與data的優(yōu)先級根據(jù) vue 的源碼,props 的優(yōu)先級要高于 data,也就是說當 props 和 data 中有同名屬性時,最終會渲染 data 中的而不是 props 中的那個
異步組件:在組件的 components 中,通過
() => import(Component)導入的組件就是異步組件動態(tài)組件:需要配合 keep-alive 使用,通過給組件添加
:is屬性來指定
七、其他需要熟悉用法的功能
- 自定義指令
- 插槽與作用域插槽
- 渲染函數(shù)(比較高級的用法,包括在 Vue 中寫 JSX)
- 過濾器(Vue 3 廢棄了,vue2中用的也不算多)
八、$nextTick
簡單的來說,nextTick 的工作原理就是將傳入的回調(diào)收集起來,等到 DOM 加載完成或者watcher觸發(fā)之后再調(diào)用。因為是用的依賴收集的機制,所以先被收集的會先執(zhí)行,所以如果多個 nextTick 嵌套時,外層的nextTick 會先執(zhí)行
Vue 3 新增的一些值得關注的特性
- Composition API (重點)
- setup 方法
-
<script setup>語法糖 - 在 Composition API 中慎用解構(gòu)賦值(可能導致響應性丟失),或者需要配合 toRefs 使用
- Teleport內(nèi)置組件 (了解用法)
- 在
<style>標簽中使用 JS 變量 - 深度選擇器的變更
- 樣式的插槽選擇器與全局選擇器