Vue3 新特性
Vue3 新特性
- 首先是向下相容,Vue3 支援大多數 Vue2 的特性。甚至就拿 Vue2 的語法開發 Vue3,也是沒有任何問題的。
-
效能的提升,每個人都希望使用的框架更快,更輕。Vue3 做到了,給開發者一個極致的體驗。官方網站給出的資料是:打包大小減少 41%,初次渲染快 55%,更新快 133%,記憶體使用減少 54%。
-
新推出的Composition API ,在 Vue2 中遇到的問題就是複雜元件的程式碼變的非常麻煩,甚至不可維護。說白了就是封裝不好,重用不暢。這個Composition API一推出,立馬解決了這個問題。它是一系列 API 的合集。
-
其他新特性:Teleport(瞬移元件)、Suspense(解決非同步載入元件問題)和全域性 API 的修改和優化。
-
更好TypeScript支援,Vue3 的原始碼就是使用TypeScript進行開發的。所以在新的版本上使用TS也更加順暢無阻。
一、composition-api
Vue在2.x中編寫程式碼要按照一定的模板,比如資料就只能放在data()中,方法只能放在methods中,按照模板編寫程式碼對於新手來講可能是好事,但是一旦專案變大,維護起來就顯得很困難。
下圖的左邊圖示,即Vue2使用的Options-api,圖中相同的顏色對應是元件的一種功能,可以看到為了實現一種功能,Options-api所寫的程式碼是非常分散的。
如果元件邏輯複雜,程式碼量多,我們新增新程式碼不光要不停的上下滑動,而且在後期程式碼維護中,閱讀起來也變得十分的困難,因為實現一種功能的程式碼並沒有集中在一起。另外就是作為一個新接手的開發人員,在茫茫的 method、data、computed 等選項中一目瞭然的發現這個變數是屬於哪個功能是比較困難的 。
而在Composition-api中,我們可以把實現一種功能的程式碼寫在一起,甚至還可以把它們單獨抽取在一個js檔案或者一個函式中。在js檔案中也可以引用Composition-api的生命週期函式。這將極大的提高程式碼的可維護性。這樣就可以更好的提取和重用多個元件之間的邏輯。
優劣比較:
-
在邏輯組織和邏輯複用方面,Composition API是優於Options API,因為Composition API幾乎是函式,會有更好的型別推斷。
-
Composition API對 tree-shaking 友好,程式碼也更容易壓縮。
-
Composition API中見不到this的使用,減少了this指向不明的情況。
-
如果是小型元件,可以繼續使用Options API,也是十分友好的。
1、setup
setup 函式是一個新的元件選項。作為在元件內使用 Composition API 的入口點。 新的 setup 選項在元件被建立之前執行,一旦 props 被解析完成,它就將被作為組合式 API 的入口。
setup函式的引數
我們先來研究一個setup函式的引數,它主要有兩個引數:
- 第一個引數:props
- 第二個引數:context
props非常好理解,它其實就是父元件傳遞過來的屬性會被放到props物件中,我們在setup中如果需要使用,那麼就可以直接通過props引數獲取:
- 對於定義props的型別,我們還是和之前的規則是一樣的,在props選項中定義;
- 並且在template中依然是可以正常去使用props中的屬性,比如message;
- 如果我們在setup函式中想要使用props,那麼不可以通過 this 去獲取(後面我會講到為什麼);
- 因為props有直接作為引數傳遞到setup函式中,所以我們可以直接通過引數來使用即可;
另外一個引數是context,我們也稱之為是一個SetupContext,它裡面包含三個屬性:
- attrs:所有的非prop的attribute;
- slots:父元件傳遞過來的插槽(這個在以渲染函式返回時會有作用);
- emit:當我們元件內部需要發出事件時會用到emit(因為我們不能訪問this,所以不可以通過 this.$emit發出事件);
setup函式的返回值
setup既然是一個函式,那麼它也可以有返回值,它的返回值用來做什麼呢?
- setup的返回值可以在模板template中被使用;
- 也就是說我們可以通過setup的返回值來替代data選項;
甚至是我們可以返回一個執行函式來代替在methods中定義的方法:
```js
```
setup不可以使用this
官方關於this有這樣一段描述:
-
表達的含義是this並沒有指向當前元件例項;
-
並且在setup被呼叫之前,data、computed、methods等都沒有被解析;
-
所以無法在setup中獲取this;
2、Ref 和 Reactive
在我看來 ref 和 reactice 都是用來建立響應式物件的。 - reactive 接受的引數是一個物件或陣列型別。如果是陣列型別會轉換成proxy物件。 - ref 一般建立一個基本型別變數,有一個 .value屬性,可以通過其對值進行讀取或修改。 - reactive 在組合函式返回時記得新增上 ’...toRefs(state)‘以保持響應性,對物件解構或展開後會失去響應性,所以需要使用roRefs()把reactive型別轉為ref型別。 - ref 可以用於子元件的ref屬性使用。(後面會提到) ```js
``` 以下是兩種關於Ref ,Reactive的風格建議
- 就像你在普通 JavaScript 中區別宣告基礎型別變數與物件變數時一樣區別使用 ref 和 reactive。我們推薦你在此風格下結合 IDE 使用型別系統。
- 所有的地方都用 reactive,然後記得在組合函式返回響應式物件時使用 toRefs。這降低了一些關於 ref 的心智負擔,但並不意味著你不需要熟悉這個概念。
3、computed 、watch、watchEffect
```js
```
watchEffect
- watch是:既要指明監視的屬性,也要指明監視的回撥。
- watchEffect是:不用指明監視哪個屬性,監視的回撥中用到哪個屬性,那就監視哪個屬性。
這個函式的功能和計算屬性差不多,但是 - computed注重的計算出來的值(回撥函式的返回值),所以必須要寫返回值。 - watchEffect更注重的是過程(回撥函式的函式體),所以不用寫返回值。
```js
``` - itemRefs 不必是陣列:它也可以是一個物件,其 ref 會通過迭代的 key 被設定。 - 如果需要,itemRef 也可以是響應式的且可以被監聽。
6、props emit ref
直接上程式碼吧 ~
```html
```
7、provide 和 inject
provide 和inject 是vue提供的一對API 這對API 可以實現元件之間的通訊 無論層級有多深 都可以通過這對API 來實現
provide
在 setup() 中使用 provide 時,我們首先從 vue 顯式匯入 provide 方法。這使我們能夠呼叫 provide 來定義每個 property。
provide 函式允許你通過兩個引數定義 property:
- name (
```js
```
inject
在 setup() 中使用 inject 時,也需要從 vue 顯式匯入。匯入以後,我們就可以呼叫它來定義暴露給我們的元件方式。 inject 函式有兩個引數: - 要 inject 的 property 的 name - 預設值 (可選)
```js
```
響應式
- 新增響應性: 為了增加 provide 值和 inject 值之間的響應性,我們可以在 provide 值時使用 ref 或 reactive。
```js
``` 現在,如果這兩個 property 中有任何更改,子元件中的值也將自動更新!
- 修改響應式 property:
當使用響應式 provide / inject 值時,
官方中
建議儘可能將對響應式 property 的所有修改限制在定義 provide 的元件內部。
```js // 父元件 export default { setup() { const location = ref('North Pole') const geolocation = reactive({ longitude: 90, latitude: 135 })
// 修改provide中值的方法
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', location)
provide('geolocation', geolocation)
provide('updateLocation', updateLocation)
} }
// 子元件 export default { setup() { const userLocation = inject('location', 'The Universe') const userGeolocation = inject('geolocation') // 子元件呼叫父元件中修改值的方法 const updateUserLocation = inject('updateLocation')
return {
userLocation,
userGeolocation,
updateUserLocation
}
} } ```
如果要確保通過 provide 傳遞的資料不會被 inject 的元件更改,官方建議對提供者的 property 使用 readonly。
```js import { provide, reactive, readonly, ref } from 'vue' export default { setup() { const location = ref('North Pole') const geolocation = reactive({ longitude: 90, latitude: 135 })
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', readonly(location))
provide('geolocation', readonly(geolocation))
provide('updateLocation', updateLocation)
} }
```
8、
單檔案元件 Composition API 語法糖 (
```
9、style 特性
scoped
當
```
TIP
通過 v-html 建立的 DOM 內容不會被作用域樣式影響,但你仍然可以使用深度選擇器來設定其樣式。
module
<style module>
標籤會被編譯為 CSS Modules 並且將生成的 CSS 類作為 $style 物件的鍵暴露給元件:
```js
``` 自定義注入名稱:
```js
``` 與組合式 API 一同使用: 注入的類可以通過 useCssModule API 在 setup() 和
```
這個語法同樣也適用於
```
單檔案元件狀態驅動的 CSS 變數 (
```
10、getCurrentInstance
getCurrentInstance()
是Vue3.x中的核心方法,用於訪問例項上下文的router及vuex等。 1. 概述:一個很重要的方法,獲取當前元件的例項、上下文來操作router和vuex等。 2. 引入:由vue提供,按需引入:import { getCurrentInstance} from 'vue'; 3. 使用:獲取當前元件的上下文,推薦使用:const { proxy } = getCurrentInstance()。```js import { getCurrentInstance } from 'vue'; // 獲取當前元件例項 const instance = getCurrentInstance();
// 獲取當前元件的上下文,下面兩種方式都能獲取到元件的上下文。 const { ctx } = getCurrentInstance(); // 方式一,這種方式只能在開發環境下使用,生產環境下的ctx將訪問不到 const { proxy } = getCurrentInstance(); // 方式二,此方法在開發環境以及生產環境下都能放到元件上下文物件(推薦) // ctx 中包含了元件中由ref和reactive建立的響應式資料物件,以及以下物件及方法; proxy.$attrs proxy.$data proxy.$el proxy.$emit proxy.$forceUpdate proxy.$nextTick proxy.$options proxy.$parent proxy.$props proxy.$refs proxy.$root proxy.$slots proxy.$watch ```
二、vue3周邊生態
1、vue-router
vue2.x中,可以通過this.$router或者this.$route來獲取或者操作路由。
在vue3.0中,引入了Composition-api。在setup函式中無法使用this獲取元件例項。新版本的vue-router也提供了支援Composition-api的hooks,例如useRouter,useRoute函式。
```js import {onMounted} from 'vue' import {useRoute, useRouter} from "vue-router";
export default { setup() { const router = useRouter() const route = useRoute()
onMounted(() => { const {id = ''} = route.params }) function pushWithQuery(query) { router.push('/index') }
}, } ```
另外,vue-router還提供了支援的Composition-api的兩個路由守衛:update and leave - beforeRouteLeave:離開當前頁面路由時觸發,return false則阻止跳轉,next中不能寫引數 - beforeRouteUpdate:動態路由 只有引數發生變化是才執行(通俗理解及跳轉頁面時)
```js import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
export default { setup() { onBeforeRouteLeave((to, from) => { const answer = window.confirm( 'Do you really want to leave? you have unsaved changes!' ) if (!answer) return false })
const userData = ref() onBeforeRouteUpdate(async (to, from) => { if (to.params.id !== from.params.id) { userData.value = await fetchUser(to.params.id) } })
}, } ```
2、vuex
```js import { useStore } from 'vuex'
export default { setup() { const store = useStore()
onMounted(() => { const data = store.state.someData }) const handleClick = () => { store.commit('CHANGE_DATA', { a: 1}) }
}, }
```
三、其他
1、Teleport
Teleport 在國內大部分都翻譯成了瞬間移動元件或任意傳送門,也有把這個函式叫獨立元件。 是一種能夠將我們的模板移動到
DOM
中Vue app
之外的其他位置的技術。場景:像
modals
,toast
等這樣的元素,很多情況下,我們將它完全的和我們的 Vue 應用的 DOM 完全剝離,管理起來反而會方便容易很多。原因在於如果我們巢狀在 Vue 的某個元件內部,那麼處理巢狀元件的定位、
z-index
和樣式就會變得很困難。另外,像
modals
,toast
等這樣的元素需要使用到 Vue 元件的狀態(data
或者props
)的值。這就是 Teleport 派上用場的地方。我們可以在元件的邏輯位置寫模板程式碼,這意味著我們可以使用元件的 data 或 props。然後在 Vue 應用的範圍之外渲染它。
使用
Teleport方法,可以把Dialog元件渲染到你任意想渲染的外部Dom上,不必巢狀再#app裡了,這樣就不會互相干擾了。你可以把Teleport看成一個傳送門,把你的元件傳送到你需要的地方。 teleport元件和其它元件沒有任何其它的差異,用起來都是一樣的。
- 首先我們在
index.html
中新增我們需要傳送到的位置。```html
``` - 將編寫的元件包裝在 teleport 元件中,還需要指定一個 to 屬性,為該屬性分配一個查詢選擇器,以標識目標元素。
```html
```我是一個 modal 文案2、Suspense
等待非同步元件時渲染一些額外內容,讓應用有更好的使用者體驗。
試驗性
Suspense 是一個試驗性的新特性,其 API 可能隨時會發生變動。特此宣告,以便社群能夠為當前的實現提供反饋。
生產環境請勿使用。
以上是官方的警告!
使用: - 首先我們先寫一個非同步元件 注意點:如果你要使用Suspense的話,要返回一個promise物件,而不是原來的那種JSON物件。
```js
```
- 使用suspense元件
```js
export default { components: { AsyncShow: defineAsyncComponent(() => import('./AsyncShow.vue')) } }
```
- 處理非同步請求錯誤
在非同步請求中必須要作的一件事情,就是要捕獲錯誤,因為我們沒辦法後端給我們返回的結果,也有可能服務不通,所以一定要進行捕獲異常和進行處理。
在vue3.x的版本中,可以使用onErrorCaptured這個鉤子函式來捕獲異常。在使用這個鉤子函式前,需要先進行引入.
```js
import { ref, defineAsyncComponent, onErrorCaptured} from "vue";
export default { components: { AsyncShow: defineAsyncComponent(() => import('./AsyncShow.vue')) }, setup() { const error = ref(null); onErrorCaptured(e => { error.value = e; return false; }); return { error }; } } ``` 有了onErrorCaptured就可以直接在setup()函式中直接使用了。鉤子函式要求我們返回一個布林值,代表錯誤是否向上傳遞。這裡的false一方面表示:錯誤不會冒泡給父元件;另一方面表示vue將停止該錯誤的傳播。
3、片段(Fragment)
在 Vue2.x 中, template中只允許有一個根節點:
<template> <div> <span></span> <span></span> </div> </template>
但是在 Vue3.x 中,你可以直接寫多個根節點:<template> <span></span> <span></span> </template>
最後的最後
最後的最後給大家推薦幾個vue3相關網址 - 第一個vue3的官網:https://staging-cn.vuejs.org/ - 一個集合了vue3很多相關技術棧的網址:https://vue3js.cn/ - 一個前端技術棧博主J技術胖:https://www.jspang.com/article/64#toc0