Vue3常用API總結

因為這個月的月初給自己定了個小目標,學完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')
復制代碼

利用了 importexport 的導入導出語法,實現了按需打包模塊的功能,項目打包后的文件體積明顯小了很多

這也是我們本文需要對 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中,我們訪問 dataprops 中的變量,都是通過類似 this.number 這樣的形式去獲取的,但要特別注意的是,在setup中,this 指向的是 undefined,也就是說不能再向Vue2一樣通過 this 去獲取變量了

那么到底該如何獲取到 props 中的數據呢?

其實 setup 函數還有兩個參數,分別是 props 、context,前者存儲著定義當前組件允許外界傳遞過來的參數名稱以及對應的值;后者是一個上下文對象,能從中訪問到 attr 、emit 、slots

其中 emit 就是我們熟悉的Vue2中與父組件通信的方法,可以直接拿來調用

(2)生命周期

Vue2中有 beforeCreatecreated 、beforeMount 、mountedbeforeUpdate 等生命周期函數

而在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 函數代替了 beforeCreatecreated 兩個生命周期函數,因此我們可以認為它的執行時間在beforeCreatecreated 之間

(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 包裝過的

那么我們到底該如何選擇 refreactive 呢?

建議:

  1. 基本類型值(StringNmuber 、Boolean 等)或單值對象(類似像 {count: 3} 這樣只有一個屬性值的對象)使用 ref
  2. 引用類型值(ObjectArray)使用 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>
復制代碼

我們分別用 reftoRefobj 中的 count 轉化為響應式,并聲明了兩個方法分別使 count 值增加,每次增加后打印一下原始值 obj 和被包裝過的響應式數據對象,同時還要看看視圖的變化

ref:

[圖片上傳中...(image-c23a78-1605864697237-14)]

可以看到,在對響應式數據的值進行 +1 操作后,視圖改變了,原始值未改變,響應式數據對象的值也改變了,這說明 ref 是對原數據的一個拷貝,不會影響到原始值,同時響應式數據對象值改變后會同步更新視圖

toRef:

[圖片上傳中...(image-4a5589-1605864697237-13)]

可以看到,在對響應式數據的值進行 +1 操作后,視圖未發生改變,原始值改變了,響應式數據對象的值也改變了,這說明 toRef 是對原數據的一個引用,會影響到原始值,但是響應式數據對象值改變后會不會更新視圖

總結:

  1. ref 是對傳入數據的拷貝;toRef 是對傳入數據的引用
  2. 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 方法是用于獲取 refreactive 對象的原始數據的

先來看一段代碼

<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 方法可以將原始數據標記為非響應式的,即使用 refreactive 將其包裝,仍無法實現數據響應式,其接收一個參數,即原始數據,并返回被標記后的數據

我們來看一下代碼

<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中的 provideinject 作用相同,只不過在Vue3中需要手動從 vue 中導入

這里簡單說明一下這兩個方法的作用:

  • provide :向子組件以及子孫組件傳遞數據。接收兩個參數,第一個參數是 key,即數據的名稱;第二個參數為 value,即數據的值
  • inject :接收父組件或祖先組件傳遞過來的數據。接收一個參數 key,即父組件或祖先組件傳遞的數據名稱

假設這有三個組件,分別是 A.vue 、B.vue 、C.vue,其中 B.vueA.vue 的子組件,C.vueB.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

watchwatchEffect 都是用來監視某項數據變化從而執行指定的操作的,但用法上還是有所區別

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 的區別主要有以下幾點:

  1. 不需要手動傳入依賴
  2. 每次初始化時會執行一次回調函數來自動獲取依賴
  3. 無法獲取到原值,只能得到變化后的值

來看一下該方法如何使用:

<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.countstate.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 包含的內容太多,所以沒截完整,但是主要的內容都在圖上了,我們重點來看一下 ctxproxy,因為這兩個才是我們想要的 this 的內容

[圖片上傳中...(image-fa3e9c-1605864697235-2)]

[圖片上傳中...(image-e6fbec-1605864697235-1)]

可以看到 ctxproxy 的內容十分類似,只是后者相對于前者外部包裝了一層 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>
復制代碼

我們來看一下打印結果

image.png

然后接下來就可以像之前一樣正常使用 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>
復制代碼

獲取元素的操作一共分為以下幾個步驟:

  1. 先給目標元素的 ref 屬性設置一個值,假設為 el
  2. 然后在 setup 函數中調用 ref 函數,值為 null,并賦值給變量 el,這里要注意,該變量名必須與我們給元素設置的 ref 屬性名相同
  3. 把對元素的引用變量 el 返回(return)出去

補充:設置的元素引用變量只有在組件掛載后才能訪問到,因此在掛載前對元素進行操作都是無效的

當然如果我們引用的是一個組件元素,那么獲得的將是該組件的實例對象,這里就不做過多的演示了

三、結束語

本文也是筆者對Vue3的學習與理解。因為在之前學習的過程中也查閱了大量的文檔資料,并不斷地測試摸索,以及在Vue3項目中的心得體會,都讓我對Vue3有了更深的認識,與此同時,我在各個社區或者是社交群里都發現很多小伙伴對Vue3的API都不太熟悉,甚至不知道有這些API,所以我就寫下了這篇總結文章,將我所知道、所理解的都分享給大家

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容