Vue3.0(B站李南江)
參考:
https://www.yuque.com/gdnnth/vue-v3/xvrc7e
https://www.jianshu.com/p/4725441aff5f
https://blog.csdn.net/wanghuan1020/article/details/109362810
一、 Vue3.0六大兩點
- Performance:效能比Vue2.x快1.2~2倍
- Treeshakingsupport:按需編譯,體積比Vue2.x更小
- CompositionAPI:組合API(類似ReactHooks)
- BetterTypeScriptsupport:更好的Ts支援
- CustomRendererAPI:暴露了自定義渲染API
- Fragment,Teleport(Protal),Suspense:更先進的元件
二、VUE3.0是如何變快的
1.diff方法優化:http://vue-next-template-explorer.netlify.app/
-
- Vue2中的虛擬dom是進行全量的對比
- Vue3新增了靜態標記(PatchFlag)
在與上次虛擬節點進行對比時候,只對比帶有patchflag的節點
並且可以通過flag的資訊得知當前節點要對比的具體內容
在建立虛擬dom的時候,會根據DOM中的內容會不會發生變化,新增靜態標記
2.hoistStatic靜態提升
-
- Vue2中無論元素是否參與更新,每次都會重新建立,然後再渲染
- Vue3中對不參與更新的元素,會做靜態提升,只會被建立一次,在渲染時直接複用即可
- Vue2中無論元素是否參與更新,每次都會重新建立,然後再渲染
3.cacheHandlers事件偵聽快取
-
- 預設情況下onClick會被視為動態繫結,所以每次都會去追蹤它的變化
- 但是因為是同一個函式,所以沒有追蹤變化,直接快取起來複用即可
- 在Vue3中的diff演算法中,只有存在靜態標記的節點才會進行追蹤,事件偵聽快取本質上是去除了不必要的diff比較
4.SSR渲染
-
- 當有大量靜態的內容時候,這些內容會被當做純字串推進一個Buffer裡面,即使存在動態的繫結,會通過模板插值嵌入進去。這樣會比通過虛擬dom來渲染快上很多。
- 當靜態內容達到一定量級時候,會使用_createStaticVNode方法在客戶端dom來渲染一個staticnode,這些靜態node,會被直接innerHtml,就不需要建立物件,然後根據物件渲染。
三、VUE3.0的建立
1.VUE-CLI
1 npm install -g @vue/cli
2 vue create projectName
3 cd projectName
4 npm run serve
2.Webpack
git clone https://github.com/vuejs/vue-next-webpack-preview.git projectName
cd projectName
npm install
npm run dev
3.Vite
Vite是Vue作者開發的一款意圖取代webpack的工具
其實現原理是利用ES6的import會發送請求去載入檔案的特性,攔截這些請求,做一些預編譯,省去webpack冗長的打包時間
// 1. 安裝Vite
npm install -g create-vite-app
// 2. 建立Vue3專案
create-vite-app projectName
// 3. 安裝依賴執行專案
cd projectName
npm install
npm run dev
四、CompositionAPI
<template>
<div>
<p>{{ count }}</p>
<button @click="myFun">按鈕</button>
</div>
</template>
<script>
// ref函式只能監聽簡單型別的變化,不能監聽複雜型別的變化(物件,陣列),監聽複雜型別引入並使用reactive
import { ref } from 'vue'
export default {
name: 'App',
// setup 函式是組合api的入口函式,執行時間在beforeCreate和created之間
setup() {
// 定義了一個count變數,初始值為0
// 該變數發生改變後,Vue會自動更新UI
let count = ref(0)
// 在組合api中,如果定義方法,不需要定義到methods,直接定義即可
function myFun() {
count.value += 1 // 修改值,count.value而不是count
}
/**
* 注意點:
* 在組合api中定義的變數/方法,要想在外界使用,必須通過return { xxx, xxx } 暴露出去
*/
return { count, myFun }
},
}
</script>
1.setup注意點
-
- 由於在執行setup函式的時候,還沒有執行created生命週期方法,所以在setup函式中,是無法使用data和methods
- 由於不能再setup函式中使用data和methods,所以Vue為了避免我們的錯誤使用,它直接將setup函式中的this修改成了undefined
- setup函式只能是同步的,不能是非同步的,async setup() {} 錯誤使用
2.ref函式
2.1.什麼是ref?
ref和reactive一樣,也是用來實現響應式資料的方法
由於reactive必須傳遞一個物件,所以導致在企業開發中,如果我們只想讓某個變數實現響應式的時候會非常麻煩,
所以Vue3就給我們提供了ref方法,實現對簡單值的監聽
2.2.ref本質
ref底層的本質其實還是reactive,系統會自動根據我們給ref傳入的值將它轉換成ref(xx)->reactive({value:xx})
2.3.ref注意點
在Vue中使用ref的值不用通過value獲取
在JS中使用ref的值必須通過value獲取
3.reactive
<template>
<div>
<p>{{time}}</p>
<button @click="myFn">按鈕</button>
</div>
</template>
<script>
/*
reactive的用法與ref的用法相似,也是將資料變成響應式資料,當資料發生變化時UI也會自動更新。
不同的是ref用於基本資料型別,而reactive是用於複雜資料型別,比如物件和陣列
*/
// toRefs解構
import { reactive,toRefs } from 'vue'
export default {
name: 'App',
setup() {
// 賦值
let state = reactive({
time: new Date(),
})
function myFn() {
/*
reactive中傳遞的引數必須是json物件或者陣列,如果傳遞了其他物件(比如new Date()),在預設情況下修改物件,
介面不會自動更新,如果也需要具有響應式,可以通過重新賦值的方式實現
*/
const newTime = new Date(state.time.getTime())
newTime.setDate(newTime.getDate() + 1)
state.time = newTime
// state.time.setDate(state.time.getDate() + 1) ,頁面不更新
console.log(state) // reactive將傳遞的物件包裝成了proxy物件
}
return {
...toRefs(state),
myFn,
}
},
}
</script>
3.1.什麼是reactive?
-
- reactive是Vue3中提供的實現響應式資料的方法
- 在Vue2中響應式資料是通過defineProperty來實現的,而在Vue3中響應式資料是通過ES6的Proxy來實現的
3.2.reactive注意點
-
- reactive引數必須是物件(json/array)
- 如果給reactive傳遞了其他物件
- 預設情況下修改物件,介面不會自動更新
- 如果想更新,可以通過重新賦值的方式
四、相關 API
1.isRef和isReactive ,判斷一個數據是ref型別還是reactive型別
import { ref, reactive, isRef, isReactive } from 'vue'
export default {
name: 'App',
setup() {
let age = ref(18)
// let age = reactive({
// value: 18
// })
function myFun() {
console.log(isReactive(age))
console.log(isRef(age))
age.value += 2
}
return {
age,
myFun
}
}
}
2.只讀:readonly,shallowReadonly,isReadonly
-
- readonly:用於建立一個只讀的資料,並且是遞迴只讀
- shallowReadonly:用於建立一個只讀資料,但是不是遞迴只讀的
- isReadonly:對於readonly和shallowReadonly建立的資料,返回結果均為true
- const和readonly的區別:
const:賦值保護,不能給變數重新賦值
readonly:屬性保護,不能給屬性重新賦值
import { readonly, isReadonly, shallowReadonly } from 'vue'
export default {
name: 'App',
setup() {
// 用於建立一個只讀的資料,並且是遞迴只讀
let state = readonly({
name: 'lnj',
attr: {
age: 18,
height: 1.88,
},
})
function myFn() {
state.name = '知播漁'
state.attr.age = 666
state.attr.height = 1.66
console.log(state)
console.log(isReadonly(state))
}
return {
state,
myFn,
}
},
}
3.遞迴監聽與非遞迴監聽
遞迴監聽
預設情況下,無論是通過ref還是reactive都是遞迴監聽
每一層都包裝成了一個proxy物件
遞迴監聽存在的問題
如果資料量比較大,非常消耗效能
非遞迴監聽
shallowReactive
非遞迴監聽下,第一層被包裝成了proxy
這意味著:只有第一層的資料發生改變,才會觸發UI介面的更新
shallowRef
如果是通過shallowRef建立資料,那麼Vue監聽的是.value的變化,並不是第一層的變化
如果想在修改其內部資料後觸發介面的更新,可以呼叫triggerRef方法
應用場景
一般情況下使用ref和reactive即可
只有在需要監聽的資料量比較大的時候,我們才使用shallowRef/shallowReactive
<template>
<div>
<p>{{ state.a }}</p>
<p>{{ state.gf.b }}</p>
<p>{{ state.gf.f.c }}</p>
<p>{{ state.gf.f.s.d }}</p>
<button @click="myFun">按鈕</button>
</div>
</template>
<script>
import { ref, shallowRef, triggerRef } from 'vue'
export default {
name: 'App',
setup() {
// shallowRef 本質上還是 shallowReative
// shallowRef(10) -> shallowReactive({ value: 10 })
// 所以如果是通過 shallowRef 建立的資料,它監聽的是 .value 的變化
let state = shallowRef({
a: 'a',
gf: {
b: 'b',
f: {
c: 'c',
s: {
d: 'd'
}
}
}
})
function myFun() {
/**
* triggerRef
* 注意點:
* + Vue3 只提供了 triggerRef 方法,沒有提供 triggerReactive 方法
* + 所以如果是 reactive 型別的資料,那麼是無法主動觸發介面更新的
*/
// state.value.a = 1
// state.value.gf.b = 2
state.value.gf.f.c = 3
state.value.gf.f.s.d = 4 // 如果想在修改該資料時,觸發介面的更新,可以呼叫 triggerRef 方法主動觸發
triggerRef(state)
/**
* shallowRef
* 注意點:
* + 如果是通過 shallowRef 建立資料,那麼 Vue監聽的是 .value 的變化,因為底層本質上.value才是第一層
*/
// state.value = {
// a: '1',
// gf: {
// b: '2',
// f: {
// c: '3',
// s: {
// d: '4'
// }
// }
// }
// }
console.log(state)
console.log(state.value.gf)
console.log(state.value.gf.f)
console.log(state.value.gf.f.s)
}
return {
state,
myFun
}
}
}
</script>
4.toRef與toRefs
- ref->複製,修改響應式資料不會影響以前的資料
- toRef->深拷貝引用,修改響應式資料會影響以前的資料
- ref->資料發生改變,介面就會自動更新
- toRef->資料發生改變,介面也不會自動更新
- toRefs->解構
5.customRef函式
<template>
<div>
<p>{{age}}</p>
<button @click="myFun">按鈕</button>
</div>
</template>
<script>
/**
* custemRef返回一個 ref 物件,可以顯式的控制依賴追蹤和觸發響應
*/
import { ref, customRef } from 'vue'
function myRef(value) {
return customRef((track, trigger) => {
// track -> 追蹤 trigger -> 觸發
return {
get() {
track() // 告訴 Vue 這個資料是需要追蹤變化的
console.log('get', value)
return value
},
set(newValue) {
console.log('set', newValue)
value = newValue
trigger() // 告訴 Vue 觸發介面更新
}
}
})
}
export default {
name: 'App',
setup() {
// let age = ref(18) // reactive({value: 18})
let age = myRef(18)
function myFun() {
age.value += 1
}
return { age, myFun }
}
}
</script>