因為這個月的月初給自己定了個小目標,學完Vue3的基本使用,并使用Vue3親手做一個小項目(稍微透露一下,我制作的是一個小工具,現在已經完成了90%了,這個月月底之前會通過博客的形式向大家展示,并且提供設計思路,大家敬請期待……),本文會頻繁地對比Vue2來介紹Vue3,也將對各個API結合代碼實例講解,這既是對自己知識的總結,也希望能幫助到大家
一、前言
大家都知道,現在Vue3的各個版本已經陸續發布了,并且有很多的團隊已經著手各個庫的開發與Vue2向Vue3的升級,我們當然也不能落后,所以趕緊將你手中的Vue2升級到Vue3,跟著本文一起學習新的API吧
升級的方法可以點擊本文開頭的文章,在上一篇文章中有個保姆級別的教程告訴大家如何升級
二、正文
Vue2每次都把整個Vue導入,例如Vue2的 main.js
文件中的代碼
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
復制代碼
但很明顯我們的項目中不可能用到Vue所有的API,因此很多模塊其實是沒有用的
那么在Vue3中,對外暴露了很多的API供開發者使用,我們可以根據自己的需求,將所需要的API從Vue中導入。例如 main.js
中的代碼
import { createApp } from 'vue';
import App from './App.vue'
createApp(App).mount('#app')
復制代碼
利用了 import
和 export
的導入導出語法,實現了按需打包模塊的功能,項目打包后的文件體積明顯小了很多
這也是我們本文需要對 Vue3 API
進行詳細了解的原因
(1)setup
setup
函數也是 Compsition API
的入口函數,我們的變量、方法都是在該函數里定義的,來看一下使用方法
<template>
<div id="app">
<p>{{ number }}</p>
<button @click="add">增加</button>
</div>
</template>
<script>
// 1\. 從 vue 中引入 ref 函數
import {ref} from 'vue'
export default {
name: 'App',
setup() {
// 2\. 用 ref 函數包裝一個響應式變量 number
let number = ref(0)
// 3\. 設定一個方法
function add() {
// number是被ref函數包裝過了的,其值保存在.value中
number.value ++
}
// 4\. 將 number 和 add 返回出去,供template中使用
return {number, add}
}
}
</script>
復制代碼
上述代碼中用到了 ref
函數,下面會詳細講解,在這里你只需要理解它的作用是包裝一個響應式的數據即可,并且你可以將 ref
函數包裝過的變量看作是Vue2 data
中的變量
這樣就簡單實現了一個點擊按鈕數字加1的功能
在Vue2中,我們訪問 data
或 props
中的變量,都是通過類似 this.number
這樣的形式去獲取的,但要特別注意的是,在setup中,this
指向的是 undefined
,也就是說不能再向Vue2一樣通過 this
去獲取變量了
那么到底該如何獲取到 props
中的數據呢?
其實 setup
函數還有兩個參數,分別是 props
、context
,前者存儲著定義當前組件允許外界傳遞過來的參數名稱以及對應的值;后者是一個上下文對象,能從中訪問到 attr
、emit
、slots
其中 emit
就是我們熟悉的Vue2中與父組件通信的方法,可以直接拿來調用
(2)生命周期
Vue2中有 beforeCreate
、created
、beforeMount
、mounted
、beforeUpdate
等生命周期函數
而在Vue3中,這些生命周期部分有所變化,并且調用的方式也有所改變,下面放上一張變化圖來簡單了解一下
Vue2 | Vue3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestory | onBeforeUnmount |
destoryed | unMounted |
Vue3的這些生命周期調用也很簡單,同樣是先從 vue
中導入,再進行直接調用
<template>
<div id="app"></div>
</template>
<script>
// 1\. 從 vue 中引入 多個生命周期函數
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted} from 'vue'
export default {
name: 'App',
setup() {
onBeforeMount(() => {
// 在掛載前執行某些代碼
})
onMounted(() => {
// 在掛載后執行某些代碼
})
onBeforeUpdate(() => {
// 在更新前前執行某些代碼
})
onUpdated(() => {
// 在更新后執行某些代碼
})
onBeforeUnmount(() => {
// 在組件銷毀前執行某些代碼
})
unMounted(() => {
// 在組件銷毀后執行某些代碼
})
return {}
}
}
</script>
復制代碼
要特別說明一下的就是,setup
函數代替了 beforeCreate
和 created
兩個生命周期函數,因此我們可以認為它的執行時間在beforeCreate
和 created
之間
(3)reactive
reactive
方法是用來創建一個響應式的數據對象,該API也很好地解決了Vue2通過 defineProperty
實現數據響應式的缺陷
用法很簡單,只需將數據作為參數傳入即可,代碼如下
<template>
<div id="app">
<!-- 4\. 訪問響應式數據對象中的 count -->
{{ state.count }}
</div>
</template>
<script>
// 1\. 從 vue 中導入 reactive
import {reactive} from 'vue'
export default {
name: 'App',
setup() {
// 2\. 創建響應式的數據對象
const state = reactive({count: 3})
// 3\. 將響應式數據對象state return 出去,供template使用
return {state}
}
}
</script>
復制代碼
(4)ref
在介紹 setup
函數時,我們使用了 ref
函數包裝了一個響應式的數據對象,這里表面上看上去跟 reactive
好像功能一模一樣啊,確實差不多,因為 ref
就是通過 reactive
包裝了一個對象 ,然后是將值傳給該對象中的 value
屬性,這也就解釋了為什么每次訪問時我們都需要加上 .value
我們可以簡單地把 ref(obj)
理解為這個樣子 reactive({value: obj})
這里我們寫一段代碼來具體看一下
<script>
import {ref, reactive} from 'vue'
export default {
name: 'App',
setup() {
const obj = {count: 3}
const state1 = ref(obj)
const state2 = reactive(obj)
console.log(state1)
console.log(state2)
}
}
</script>
復制代碼
來看一下打印結果
[圖片上傳中...(image-ef9e20-1605864697238-15)]
注意: 這里指的
.value
是在setup
函數中訪問ref
包裝后的對象時才需要加的,在template
模板中訪問時是不需要的,因為在編譯時,會自動識別其是否為ref
包裝過的
那么我們到底該如何選擇 ref
和 reactive
呢?
建議:
- 基本類型值(
String
、Nmuber
、Boolean
等)或單值對象(類似像{count: 3}
這樣只有一個屬性值的對象)使用ref
- 引用類型值(
Object
、Array
)使用reactive
(5)toRef
toRef
是將某個對象中的某個值轉化為響應式數據,其接收兩個參數,第一個參數為 obj
對象;第二個參數為對象中的屬性名
代碼如下:
<script>
// 1\. 導入 toRef
import {toRef} from 'vue'
export default {
setup() {
const obj = {count: 3}
// 2\. 將 obj 對象中屬性count的值轉化為響應式數據
const state = toRef(obj, 'count')
// 3\. 將toRef包裝過的數據對象返回供template使用
return {state}
}
}
</script>
復制代碼
但其實表面上看上去 toRef
這個API好像非常的沒用,因為這個功能也可以用 ref
實現,代碼如下
<script>
// 1\. 導入 ref
import {ref} from 'vue'
export default {
setup() {
const obj = {count: 3}
// 2\. 將 obj 對象中屬性count的值轉化為響應式數據
const state = ref(obj.count)
// 3\. 將ref包裝過的數據對象返回供template使用
return {state}
}
}
</script>
復制代碼
乍一看好像還真是,其實這兩者是有區別的,我們可以通過一個案例來比較一下,代碼如下
<template>
<p>{{ state1 }}</p>
<button @click="add1">增加</button>
<p>{{ state2 }}</p>
<button @click="add2">增加</button>
</template>
<script>
import {ref, toRef} from 'vue'
export default {
setup() {
const obj = {count: 3}
const state1 = ref(obj.count)
const state2 = toRef(obj, 'count')
function add1() {
state1.value ++
console.log('原始值:', obj);
console.log('響應式數據對象:', state1);
}
function add2() {
state2.value ++
console.log('原始值:', obj);
console.log('響應式數據對象:', state2);
}
return {state1, state2, add1, add2}
}
}
</script>
復制代碼
我們分別用 ref
和 toRef
將 obj
中的 count
轉化為響應式,并聲明了兩個方法分別使 count
值增加,每次增加后打印一下原始值 obj
和被包裝過的響應式數據對象,同時還要看看視圖的變化
ref:
[圖片上傳中...(image-c23a78-1605864697237-14)]
可以看到,在對響應式數據的值進行 +1
操作后,視圖改變了,原始值未改變,響應式數據對象的值也改變了,這說明 ref
是對原數據的一個拷貝,不會影響到原始值,同時響應式數據對象值改變后會同步更新視圖
toRef:
[圖片上傳中...(image-4a5589-1605864697237-13)]
可以看到,在對響應式數據的值進行 +1
操作后,視圖未發生改變,原始值改變了,響應式數據對象的值也改變了,這說明 toRef
是對原數據的一個引用,會影響到原始值,但是響應式數據對象值改變后會不會更新視圖
總結:
-
ref
是對傳入數據的拷貝;toRef
是對傳入數據的引用 -
ref
的值改變會更新視圖;toRef
的值改變不會更新視圖
(6)toRefs
了解完 toRef
后,就很好理解 toRefs
了,其作用就是將傳入的對象里所有的屬性的值都轉化為響應式數據對象,該函數支持一個參數,即 obj
對象
我們來看一下它的基本使用
<script>
// 1\. 導入 toRefs
import {toRefs} from 'vue'
export default {
setup() {
const obj = {
name: '前端印象',
age: 22,
gender: 0
}
// 2\. 將 obj 對象中屬性count的值轉化為響應式數據
const state = toRefs(obj)
// 3\. 打印查看一下
console.log(state)
}
}
</script>
復制代碼
打印結果如下:
[圖片上傳中...(image-94f4ce-1605864697237-12)]
返回的是一個對象,對象里包含了每一個包裝過后的響應式數據對象
(7)shallowReactive
聽這個API的名稱就知道,這是一個漸層的 reactive
,難道意思就是原本的 reactive
是深層的唄,沒錯,這是一個用于性能優化的API
其實將 obj
作為參數傳遞給 reactive
生成響應式數據對象時,若 obj
的層級不止一層,那么會將每一層都用 Proxy
包裝一次,我們來驗證一下
<script>
import {reactive} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = reactive(obj)
console.log(state)
console.log(state.first)
console.log(state.first.second)
}
}
</script>
復制代碼
來看一下打印結果:
[圖片上傳中...(image-7b04e7-1605864697237-11)]
設想一下如果一個對象層級比較深,那么每一層都用 Proxy
包裝后,對于性能是非常不友好的
接下來我們再來看看 shallowReactive
<script>
import {shallowReactive} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowReactive(obj)
console.log(state)
console.log(state.first)
console.log(state.first.second)
}
}
</script>
復制代碼
來看一下打印結果:
[圖片上傳中...(image-aded97-1605864697237-10)]
結果非常的明了了,只有第一層被 Proxy
處理了,也就是說只有修改第一層的值時,才會響應式更新,代碼如下:
<template>
<p>{{ state.a }}</p>
<p>{{ state.first.b }}</p>
<p>{{ state.first.second.c }}</p>
<button @click="change1">改變1</button>
<button @click="change2">改變2</button>
</template>
<script>
import {shallowReactive} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowReactive(obj)
function change1() {
state.a = 7
}
function change2() {
state.first.b = 8
state.first.second.c = 9
console.log(state);
}
return {state}
}
}
</script>
復制代碼
來看一下具體過程:
[圖片上傳中...(image-7e28c0-1605864697237-9)]
首先我們點擊了第二個按鈕,改變了第二層的 b
和第三層的 c
,雖然值發生了改變,但是視圖卻沒有進行更新;
當我們點擊了第一個按鈕,改變了第一層的 a
時,整個視圖進行了更新;
由此可說明,shallowReactive
監聽了第一層屬性的值,一旦發生改變,則更新視圖
(8)shallowRef
這是一個淺層的 ref
,與 shallowReactive
一樣是拿來做性能優化的
shallowReactive
是監聽對象第一層的數據變化用于驅動視圖更新,那么 shallowRef
則是監聽 .value
的值的變化來更新視圖的
我們來看一下具體代碼
<template>
<p>{{ state.a }}</p>
<p>{{ state.first.b }}</p>
<p>{{ state.first.second.c }}</p>
<button @click="change1">改變1</button>
<button @click="change2">改變2</button>
</template>
<script>
import {shallowRef} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowRef(obj)
console.log(state);
function change1() {
// 直接將state.value重新賦值
state.value = {
a: 7,
first: {
b: 8,
second: {
c: 9
}
}
}
}
function change2() {
state.value.first.b = 8
state.value.first.second.c = 9
console.log(state);
}
return {state, change1, change2}
}
}
</script>
復制代碼
首先看一下被 shallowRef
包裝過后是怎樣的結構
[圖片上傳中...(image-4d7c9f-1605864697237-8)]
然后再來看看改變其值會有什么變化
[圖片上傳中...(image-7c6b67-1605864697237-7)]
我們先點擊了第二個按鈕,發現數據確實被改變了,但是視圖并沒隨之更新;
于是點擊了第二個按鈕,即將整個 .value
重新賦值了,視圖就立馬更新了
這么一看,未免也太過麻煩了,改個數據還要重新賦值,不要擔心,此時我們可以用到另一個API,叫做 triggerRef
,調用它就可以立馬更新視圖,其接收一個參數 state
,即需要更新的 ref
對象
我們來使用一下
<template>
<p>{{ state.a }}</p>
<p>{{ state.first.b }}</p>
<p>{{ state.first.second.c }}</p>
<button @click="change">改變</button>
</template>
<script>
import {shallowRef, triggerRef} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowRef(obj)
console.log(state);
function change() {
state.value.first.b = 8
state.value.first.second.c = 9
// 修改值后立即驅動視圖更新
triggerRef(state)
console.log(state);
}
return {state, change}
}
}
</script>
復制代碼
我們來看一下具體過程
[圖片上傳中...(image-c43e3d-1605864697237-6)]
可以看到,我們沒有給 .value
重新賦值,只是在修改值后,調用了 triggerRef
就實現了視圖的更新
(9)toRaw
toRaw
方法是用于獲取 ref
或 reactive
對象的原始數據的
先來看一段代碼
<template>
<p>{{ state.name }}</p>
<p>{{ state.age }}</p>
<button @click="change">改變</button>
</template>
<script>
import {reactive} from 'vue'
export default {
setup() {
const obj = {
name: '前端印象',
age: 22
}
const state = reactive(obj)
function change() {
state.age = 90
console.log(obj); // 打印原始數據obj
console.log(state); // 打印 reactive對象
}
return {state, change}
}
}
</script>
復制代碼
來看看具體過程
[圖片上傳中...(image-33b92-1605864697236-5)]
我們改變了 reactive
對象中的數據,于是看到原始數據 obj
和被 reactive
包裝過的對象的值都發生了變化,由此我們可以看出,這兩者是一個引用關系
那么此時我們就想了,那如果直接改變原始數據 obj
的值,會怎么樣呢?答案是: reactive
的值也會跟著改變,但是視圖不會更新
由此可見,當我們想修改數據,但不想讓視圖更新時,可以選擇直接修改原始數據上的值,因此需要先獲取到原始數據,我們可以使用 Vue3 提供的 toRaw
方法
toRaw
接收一個參數,即 ref
對象或 reactive
對象
<script>
import {reactive, toRaw} from 'vue'
export default {
setup() {
const obj = {
name: '前端印象',
age: 22
}
const state = reactive(obj)
const raw = toRaw(state)
console.log(obj === raw) // true
}
}
</script>
復制代碼
上述代碼就證明了 toRaw
方法從 reactive
對象中獲取到的是原始數據,因此我們就可以很方便的通過修改原始數據的值而不更新視圖來做一些性能優化了
注意: 補充一句,當
toRaw
方法接收的參數是ref
對象時,需要加上.value
才能獲取到原始數據對象
(10)markRaw
markRaw
方法可以將原始數據標記為非響應式的,即使用 ref
或 reactive
將其包裝,仍無法實現數據響應式,其接收一個參數,即原始數據,并返回被標記后的數據
我們來看一下代碼
<template>
<p>{{ state.name }}</p>
<p>{{ state.age }}</p>
<button @click="change">改變</button>
</template>
<script>
import {reactive, markRaw} from 'vue'
export default {
setup() {
const obj = {
name: '前端印象',
age: 22
}
// 通過markRaw標記原始數據obj, 使其數據更新不再被追蹤
const raw = markRaw(obj)
// 試圖用reactive包裝raw, 使其變成響應式數據
const state = reactive(raw)
function change() {
state.age = 90
console.log(state);
}
return {state, change}
}
}
</script>
復制代碼
我們來看一下在被 markRaw
方法處理過后的數據是否還能被 reactive
包裝成響應式數據
[圖片上傳中...(image-19b983-1605864697236-4)]
從圖中可以看到,即使我們修改了值也不會更新視圖了,即沒有實現數據響應式
(11)provide && inject
與 Vue2中的 provide
和 inject
作用相同,只不過在Vue3中需要手動從 vue
中導入
這里簡單說明一下這兩個方法的作用:
-
provide :向子組件以及子孫組件傳遞數據。接收兩個參數,第一個參數是
key
,即數據的名稱;第二個參數為value
,即數據的值 -
inject :接收父組件或祖先組件傳遞過來的數據。接收一個參數
key
,即父組件或祖先組件傳遞的數據名稱
假設這有三個組件,分別是 A.vue
、B.vue
、C.vue
,其中 B.vue
是 A.vue
的子組件,C.vue
是 B.vue
的子組件
// A.vue
<script>
import {provide} from 'vue'
export default {
setup() {
const obj= {
name: '前端印象',
age: 22
}
// 向子組件以及子孫組件傳遞名為info的數據
provide('info', obj)
}
}
</script>
// B.vue
<script>
import {inject} from 'vue'
export default {
setup() {
// 接收A.vue傳遞過來的數據
inject('info') // {name: '前端印象', age: 22}
}
}
</script>
// C.vue
<script>
import {inject} from 'vue'
export default {
setup() {
// 接收A.vue傳遞過來的數據
inject('info') // {name: '前端印象', age: 22}
}
}
</script>
復制代碼
(12)watch && watchEffect
watch
和 watchEffect
都是用來監視某項數據變化從而執行指定的操作的,但用法上還是有所區別
watch:watch( source, cb, [options] )
參數說明:
- source:可以是表達式或函數,用于指定監聽的依賴對象
- cb:依賴對象變化后執行的回調函數
- options:可參數,可以配置的屬性有 immediate(立即觸發回調函數)、deep(深度監聽)
當監聽 ref
類型時:
<script>
import {ref, watch} from 'vue'
export default {
setup() {
const state = ref(0)
watch(state, (newValue, oldValue) => {
console.log(`原值為${oldValue}`)
console.log(`新值為${newValue}`)
/* 1秒后打印結果:
原值為0
新值為1
*/
})
// 1秒后將state值+1
setTimeout(() => {
state.value ++
}, 1000)
}
}
</script>
復制代碼
當監聽 reactive
類型時:
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({count: 0})
watch(() => state.count, (newValue, oldValue) => {
console.log(`原值為${oldValue}`)
console.log(`新值為${newValue}`)
/* 1秒后打印結果:
原值為0
新值為1
*/
})
// 1秒后將state.count的值+1
setTimeout(() => {
state.count ++
}, 1000)
}
}
</script>
復制代碼
當同時監聽多個值時:
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'zs' })
watch(
[() => state.count, () => state.name],
([newCount, newName], [oldvCount, oldvName]) => {
console.log(oldvCount) // 舊的 count 值
console.log(newCount) // 新的 count 值
console.log(oldName) // 舊的 name 值
console.log(newvName) // 新的 name 值
}
)
setTimeout(() => {
state.count ++
state.name = 'ls'
}, 1000)
}
}
</script>
復制代碼
因為 watch
方法的第一個參數我們已經指定了監聽的對象,因此當組件初始化時,不會執行第二個參數中的回調函數,若我們想讓其初始化時就先執行一遍,可以在第三個參數對象中設置 immediate: true
watch
方法默認是漸層的監聽我們指定的數據,例如如果監聽的數據有多層嵌套,深層的數據變化不會觸發監聽的回調,若我們想要其對深層數據也進行監聽,可以在第三個參數對象中設置 deep: true
補充: watch方法會返回一個stop方法,若想要停止監聽,便可直接執行該stop函數
接下來再來聊聊 watchEffect
,它與 watch
的區別主要有以下幾點:
- 不需要手動傳入依賴
- 每次初始化時會執行一次回調函數來自動獲取依賴
- 無法獲取到原值,只能得到變化后的值
來看一下該方法如何使用:
<script>
import {reactive, watchEffect} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'zs' })
watchEffect(() => {
console.log(state.count)
console.log(state.name)
/* 初始化時打?。? 0
zs
1秒后打?。? 1
ls
*/
})
setTimeout(() => {
state.count ++
state.name = 'ls'
}, 1000)
}
}
</script>
復制代碼
從上述代碼中可以看出,我們并沒有像 watch
方法一樣先給其傳入一個依賴,而是直接指定了一個回調函數
當組件初始化時,將該回調函數執行一次,自動獲取到需要檢測的數據是 state.count
和 state.name
根據以上特征,我們可以自行選擇使用哪一個監聽器
(13)getCurrentInstance
我們都知道在Vue2的任何一個組件中想要獲取當前組件的實例可以通過 this
來得到,而在Vue3中我們大量的代碼都在 setup
函數中運行,并且在該函數中 this
指向的是 undefined
,那么該如何獲取到當前組件的實例呢?
這時可以用到另一個方法,即 getCurrentInstance
<template>
<p>{{ num }}</p>
</template>
<script>
import {ref, getCurrentInstance} from 'vue'
export default {
setup() {
const num = ref(3)
const instance = getCurrentInstance()
console.log(instance)
return {num}
}
}
</script>
復制代碼
我們來看一下其打印結果
[圖片上傳中...(image-1b311e-1605864697235-3)]
因為 instance
包含的內容太多,所以沒截完整,但是主要的內容都在圖上了,我們重點來看一下 ctx
和 proxy
,因為這兩個才是我們想要的 this
的內容
[圖片上傳中...(image-fa3e9c-1605864697235-2)]
[圖片上傳中...(image-e6fbec-1605864697235-1)]
可以看到 ctx
和 proxy
的內容十分類似,只是后者相對于前者外部包裝了一層 proxy
,由此可說明 proxy
是響應式的
(14)useStore
在Vue2中使用 Vuex,我們都是通過 this.$store
來與獲取到Vuex實例,但上一部分說了原本Vue2中的 this
的獲取方式不一樣了,并且我們在Vue3的 getCurrentInstance().ctx
中也沒有發現 $store
這個屬性,那么如何獲取到Vuex實例呢?這就要通過 vuex
中的一個方法了,即 useStore
// store 文件夾下的 index.js
import Vuex from 'vuex'
const store = Vuex.createStore({
state: {
name: '前端印象',
age: 22
},
mutations: {
……
},
……
})
// example.vue
<script>
// 從 vuex 中導入 useStore 方法
import {useStore} from 'vuex'
export default {
setup() {
// 獲取 vuex 實例
const store = useStore()
console.log(store)
}
}
</script>
復制代碼
我們來看一下打印結果
然后接下來就可以像之前一樣正常使用 vuex
了
(15)獲取標簽元素
最后再補充一個 ref
另外的作用,那就是可以獲取到標簽元素或組件
在Vue2中,我們獲取元素都是通過給元素一個 ref
屬性,然后通過 this.$refs.xx
來訪問的,但這在Vue3中已經不再適用了
接下來看看Vue3中是如何獲取元素的吧
<template>
<div>
<div ref="el">div元素</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
// 創建一個DOM引用,名稱必須與元素的ref屬性名相同
const el = ref(null)
// 在掛載后才能通過 el 獲取到目標元素
onMounted(() => {
el.value.innerHTML = '內容被修改'
})
// 把創建的引用 return 出去
return {el}
}
}
</script>
復制代碼
獲取元素的操作一共分為以下幾個步驟:
- 先給目標元素的
ref
屬性設置一個值,假設為el
- 然后在
setup
函數中調用ref
函數,值為null
,并賦值給變量el
,這里要注意,該變量名必須與我們給元素設置的ref
屬性名相同 - 把對元素的引用變量
el
返回(return)出去
補充:設置的元素引用變量只有在組件掛載后才能訪問到,因此在掛載前對元素進行操作都是無效的
當然如果我們引用的是一個組件元素,那么獲得的將是該組件的實例對象,這里就不做過多的演示了
三、結束語
本文也是筆者對Vue3的學習與理解。因為在之前學習的過程中也查閱了大量的文檔資料,并不斷地測試摸索,以及在Vue3項目中的心得體會,都讓我對Vue3有了更深的認識,與此同時,我在各個社區或者是社交群里都發現很多小伙伴對Vue3的API都不太熟悉,甚至不知道有這些API,所以我就寫下了這篇總結文章,將我所知道、所理解的都分享給大家