<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          快速使用Vue3最新的15個常用API

          共 16170字,需瀏覽 33分鐘

           ·

          2020-12-12 04:58

          之前我寫了一篇博客介紹了Vue3的新特性,簡單了解了一下Vue3都有哪些特色,并且在文末帶大家稍微體驗了一下Vue3中 Composition API 的簡單使用

          因為這個月的月初給自己定了個小目標,學完Vue3的基本使用,并使用Vue3親手做一個小項目(稍微透露一下,我制作的是一個小工具,現(xiàn)在已經(jīng)完成了90%了,這個月月底之前會通過博客的形式向大家展示,并且提供設計思路,大家敬請期待……),本文會頻繁地對比Vue2來介紹Vue3,也將對各個API結合代碼實例講解,這既是對自己知識的總結,也希望能幫助到大家

          一、前言

          大家都知道,現(xiàn)在Vue3的各個版本已經(jīng)陸續(xù)發(fā)布了,并且有很多的團隊已經(jīng)著手各個庫的開發(fā)與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供開發(fā)者使用,我們可以根據(jù)自己的需求,將所需要的API從Vue中導入。例如 main.js 中的代碼

          import?{?createApp?}?from?'vue';
          import?App?from?'./App.vue'

          createApp(App).mount('#app')

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

          這也是我們本文需要對 Vue3 API 進行詳細了解的原因

          (1)setup

          setup 函數(shù)也是 Composition API 的入口函數(shù),我們的變量、方法都是在該函數(shù)里定義的,來看一下使用方法

          <template>
          ??<div?id="app">
          ???<p>{{?number?}}p>
          ???<button?@click="add">增加button>
          ??div>
          template>

          <script>
          //?1.?從?vue?中引入?ref?函數(shù)
          import?{ref}?from?'vue'
          export?default?{
          ??name:?'App',
          ??setup()?{
          ???//?2.?用?ref?函數(shù)包裝一個響應式變量?number
          ????let?number?=?ref(0)
          ????
          ????//?3.?設定一個方法
          ????function?add()?{
          ?????//?number是被ref函數(shù)包裝過了的,其值保存在.value中
          ??????number.value?++
          ????}
          ????
          ????//?4.?將?number?和?add?返回出去,供template中使用
          ????return?{number,?add}
          ??}
          ??
          }
          script>

          上述代碼中用到了 ref 函數(shù),下面會詳細講解,在這里你只需要理解它的作用是包裝一個響應式的數(shù)據(jù)即可,并且你可以將 ref 函數(shù)包裝過的變量看作是Vue2 data 中的變量

          這樣就簡單實現(xiàn)了一個點擊按鈕數(shù)字加1的功能


          在Vue2中,我們訪問 dataprops 中的變量,都是通過類似 this.number 這樣的形式去獲取的,但要特別注意的是,在setup中,this 指向的是 undefined,也就是說不能再向Vue2一樣通過 this 去獲取變量了

          那么到底該如何獲取到 props 中的數(shù)據(jù)呢?

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

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

          (2)生命周期

          Vue2中有 beforeCreate 、created 、beforeMount 、mounted 、beforeUpdate 等生命周期函數(shù)

          而在Vue3中,這些生命周期部分有所變化,并且調(diào)用的方式也有所改變,下面放上一張變化圖來簡單了解一下

          Vue2Vue3
          beforeCreatesetup
          createdsetup
          beforeMountonBeforeMount
          mountedonMounted
          beforeUpdateonBeforeUpdate
          updatedonUpdated
          beforeDestoryonBeforeUnmount
          destoryedonUnmounted

          Vue3的這些生命周期調(diào)用也很簡單,同樣是先從 vue 中導入,再進行直接調(diào)用

          <template>
          ??<div?id="app">div>
          template>

          <script>
          //?1.?從?vue?中引入?多個生命周期函數(shù)
          import?{onBeforeMount,?onMounted,?onBeforeUpdate,?onUpdated,?onBeforeUnmount,?unMounted}?from?'vue'
          export?default?{
          ??name:?'App',
          ??setup()?{
          ????onBeforeMount(()?=>?{
          ??????//?在掛載前執(zhí)行某些代碼
          ????})

          ????onMounted(()?=>?{
          ??????//?在掛載后執(zhí)行某些代碼
          ????})

          ????onBeforeUpdate(()?=>?{
          ??????//?在更新前前執(zhí)行某些代碼
          ????})

          ????onUpdated(()?=>?{
          ??????//?在更新后執(zhí)行某些代碼
          ????})

          ????onBeforeUnmount(()?=>?{
          ??????//?在組件銷毀前執(zhí)行某些代碼
          ????})

          ????unMounted(()?=>?{
          ??????//?在組件銷毀后執(zhí)行某些代碼
          ????})

          ????return?{}
          ??}
          ??
          }
          script>

          要特別說明一下的就是,setup 函數(shù)代替了 beforeCreatecreated 兩個生命周期函數(shù),因此我們可以認為它的執(zhí)行時間在beforeCreatecreated 之間

          (3)reactive

          reactive 方法是用來創(chuàng)建一個響應式的數(shù)據(jù)對象,該API也很好地解決了Vue2通過 defineProperty 實現(xiàn)數(shù)據(jù)響應式的缺陷

          用法很簡單,只需將數(shù)據(jù)作為參數(shù)傳入即可,代碼如下

          <template>
          ??<div?id="app">
          ???
          ???{{?state.count?}}
          ??div>
          template>

          <script>
          //?1.?從?vue?中導入?reactive?
          import?{reactive}?from?'vue'
          export?default?{
          ??name:?'App',
          ??setup()?{
          ????//?2.?創(chuàng)建響應式的數(shù)據(jù)對象
          ????const?state?=?reactive({count:?3})

          ????//?3.?將響應式數(shù)據(jù)對象state?return?出去,供template使用
          ????return?{state}
          ??}
          }
          script>

          (4)ref

          在介紹 setup 函數(shù)時,我們使用了 ref 函數(shù)包裝了一個響應式的數(shù)據(jù)對象,這里表面上看上去跟 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>

          來看一下打印結果


          注意: 這里指的 .value 是在 setup 函數(shù)中訪問 ref 包裝后的對象時才需要加的,在 template 模板中訪問時是不需要的,因為在編譯時,會自動識別其是否為 ref 包裝過的

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

          建議:

          1. 基本類型值(String 、Nmuber 、Boolean 等)或單值對象(類似像 {count: 3} 這樣只有一個屬性值的對象)使用 ref
          2. 引用類型值(ObjectArray)使用 reactive

          (5)toRef

          toRef 是將某個對象中的某個值轉(zhuǎn)化為響應式數(shù)據(jù),其接收兩個參數(shù),第一個參數(shù)為 obj 對象;第二個參數(shù)為對象中的屬性名

          代碼如下:

          <script>
          //?1.?導入?toRef
          import?{toRef}?from?'vue'
          export?default?{
          ????setup()?{
          ????????const?obj?=?{count:?3}
          ????????//?2.?將?obj?對象中屬性count的值轉(zhuǎn)化為響應式數(shù)據(jù)
          ????????const?state?=?toRef(obj,?'count')
          ??
          ????????//?3.?將toRef包裝過的數(shù)據(jù)對象返回供template使用
          ????????return?{state}
          ????}
          }
          script>

          但其實表面上看上去 toRef 這個API好像非常的沒用,因為這個功能也可以用 ref 實現(xiàn),代碼如下

          <script>
          //?1.?導入?ref
          import?{ref}?from?'vue'
          export?default?{
          ????setup()?{
          ????????const?obj?=?{count:?3}
          ????????//?2.?將?obj?對象中屬性count的值轉(zhuǎn)化為響應式數(shù)據(jù)
          ????????const?state?=?ref(obj.count)
          ??
          ????????//?3.?將ref包裝過的數(shù)據(jù)對象返回供template使用
          ????????return?{state}
          ????}
          }
          script>

          乍一看好像還真是,其實這兩者是有區(qū)別的,我們可以通過一個案例來比較一下,代碼如下

          <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('響應式數(shù)據(jù)對象:',?state1);
          ????????}

          ????????function?add2()?{
          ????????????state2.value?++
          ????????????console.log('原始值:',?obj);
          ????????????console.log('響應式數(shù)據(jù)對象:',?state2);
          ????????}

          ????????return?{state1,?state2,?add1,?add2}
          ????}
          }
          script>

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

          ref:


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

          toRef:


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

          總結:

          1. ref 是對傳入數(shù)據(jù)的拷貝;toRef 是對傳入數(shù)據(jù)的引用
          2. ref 的值改變會更新視圖;toRef 的值改變不會更新視圖

          (6)toRefs

          了解完 toRef 后,就很好理解 toRefs 了,其作用就是將傳入的對象里所有的屬性的值都轉(zhuǎn)化為響應式數(shù)據(jù)對象,該函數(shù)支持一個參數(shù),即 obj 對象

          我們來看一下它的基本使用

          <script>
          //?1.?導入?toRefs
          import?{toRefs}?from?'vue'
          export?default?{
          ????setup()?{
          ????????const?obj?=?{
          ??????????name:?'前端印象',
          ??????????age:?22,
          ??????????gender:?0
          ????????}
          ????????//?2.?將?obj?對象中屬性count的值轉(zhuǎn)化為響應式數(shù)據(jù)
          ????????const?state?=?toRefs(obj)
          ??
          ????????//?3.?打印查看一下
          ????????console.log(state)
          ????}
          }
          script>

          打印結果如下:

          返回的是一個對象,對象里包含了每一個包裝過后的響應式數(shù)據(jù)對象

          (7)shallowReactive

          聽這個API的名稱就知道,這是一個淺層的 reactive,難道意思就是原本的 reactive 是深層的唄,沒錯,這是一個用于性能優(yōu)化的API

          其實將 obj 作為參數(shù)傳遞給 reactive 生成響應式數(shù)據(jù)對象時,若 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>

          來看一下打印結果:


          設想一下如果一個對象層級比較深,那么每一層都用 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>

          來看一下打印結果:


          結果非常的明了了,只有第一層被 Proxy 處理了,也就是說只有修改第一層的值時,才會響應式更新,代碼如下:

          <template>
          ?<p>{{?state.a?}}p>
          ?<p>{{?state.first.b?}}p>
          ?<p>{{?state.first.second.c?}}p>
          ?<button?@click="change1">改變1button>
          ?<button?@click="change2">改變2button>
          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>

          來看一下具體過程:

          首先我們點擊了第二個按鈕,改變了第二層的 b 和第三層的 c,雖然值發(fā)生了改變,但是視圖卻沒有進行更新;

          當我們點擊了第一個按鈕,改變了第一層的 a 時,整個視圖進行了更新;

          由此可說明,shallowReactive 監(jiān)聽了第一層屬性的值,一旦發(fā)生改變,則更新視圖

          (8)shallowRef

          這是一個淺層的 ref,與 shallowReactive 一樣是拿來做性能優(yōu)化的

          shallowReactive 是監(jiān)聽對象第一層的數(shù)據(jù)變化用于驅(qū)動視圖更新,那么 shallowRef 則是監(jiān)聽 .value 的值的變化來更新視圖的

          我們來看一下具體代碼

          <template>
          ?<p>{{?state.a?}}p>
          ?<p>{{?state.first.b?}}p>
          ?<p>{{?state.first.second.c?}}p>
          ?<button?@click="change1">改變1button>
          ?<button?@click="change2">改變2button>
          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 包裝過后是怎樣的結構


          然后再來看看改變其值會有什么變化


          我們先點擊了第二個按鈕,發(fā)現(xiàn)數(shù)據(jù)確實被改變了,但是視圖并沒隨之更新;

          于是點擊了第一個按鈕,即將整個 .value 重新賦值了,視圖就立馬更新了

          這么一看,未免也太過麻煩了,改個數(shù)據(jù)還要重新賦值,不要擔心,此時我們可以用到另一個API,叫做 triggerRef ,調(diào)用它就可以立馬更新視圖,其接收一個參數(shù) 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
          ??????????//?修改值后立即驅(qū)動視圖更新
          ??????????triggerRef(state)
          ??????????console.log(state);
          ????????}

          ????????return?{state,?change}
          ????}
          }
          script>

          我們來看一下具體過程


          可以看到,我們沒有給 .value 重新賦值,只是在修改值后,調(diào)用了 triggerRef 就實現(xiàn)了視圖的更新

          (9)toRaw

          toRaw 方法是用于獲取 refreactive 對象的原始數(shù)據(jù)的

          先來看一段代碼

          <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);?//?打印原始數(shù)據(jù)obj
          ??????????console.log(state);??//?打印?reactive對象
          ????????}

          ????????return?{state,?change}
          ????}
          }
          script>

          來看看具體過程

          我們改變了 reactive 對象中的數(shù)據(jù),于是看到原始數(shù)據(jù) obj 和被 reactive 包裝過的對象的值都發(fā)生了變化,由此我們可以看出,這兩者是一個引用關系

          那么此時我們就想了,那如果直接改變原始數(shù)據(jù) obj 的值,會怎么樣呢?答案是:reactive 的值也會跟著改變,但是視圖不會更新

          由此可見,當我們想修改數(shù)據(jù),但不想讓視圖更新時,可以選擇直接修改原始數(shù)據(jù)上的值,因此需要先獲取到原始數(shù)據(jù),我們可以使用 Vue3 提供的 toRaw 方法

          toRaw 接收一個參數(shù),即 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 對象中獲取到的是原始數(shù)據(jù),因此我們就可以很方便的通過修改原始數(shù)據(jù)的值而不更新視圖來做一些性能優(yōu)化了

          注意: 補充一句,當 toRaw 方法接收的參數(shù)是 ref 對象時,需要加上 .value 才能獲取到原始數(shù)據(jù)對象

          (10)markRaw

          markRaw 方法可以將原始數(shù)據(jù)標記為非響應式的,即使用 refreactive 將其包裝,仍無法實現(xiàn)數(shù)據(jù)響應式,其接收一個參數(shù),即原始數(shù)據(jù),并返回被標記后的數(shù)據(jù)

          我們來看一下代碼

          <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標記原始數(shù)據(jù)obj,?使其數(shù)據(jù)更新不再被追蹤
          ????????const?raw?=?markRaw(obj)???
          ????????//?試圖用reactive包裝raw,?使其變成響應式數(shù)據(jù)
          ????????const?state?=?reactive(raw)?

          ????????function?change()?{
          ??????????state.age?=?90
          ??????????console.log(state);
          ????????}

          ????????return?{state,?change}
          ????}
          }
          script>

          我們來看一下在被 markRaw 方法處理過后的數(shù)據(jù)是否還能被 reactive 包裝成響應式數(shù)據(jù)

          從圖中可以看到,即使我們修改了值也不會更新視圖了,即沒有實現(xiàn)數(shù)據(jù)響應式

          (11)provide && inject

          與 Vue2中的 provideinject 作用相同,只不過在Vue3中需要手動從 vue 中導入

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

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

          假設這有三個組件,分別是 A.vue 、B.vueC.vue,其中 B.vueA.vue 的子組件,C.vueB.vue 的子組件

          //?A.vue
          <script>
          import?{provide}?from?'vue'
          export?default?{
          ????setup()?{
          ????????const?obj=?{
          ??????????name:?'前端印象',
          ??????????age:?22
          ????????}

          ????????//?向子組件以及子孫組件傳遞名為info的數(shù)據(jù)
          ????????provide('info',?obj)
          ????}
          }
          script>

          //?B.vue
          <script>
          import?{inject}?from?'vue'
          export?default?{
          ????setup()?{?
          ????????//?接收A.vue傳遞過來的數(shù)據(jù)
          ????????inject('info')??//?{name:?'前端印象',?age:?22}
          ????}
          }
          script>

          //?C.vue
          <script>
          import?{inject}?from?'vue'
          export?default?{
          ????setup()?{?
          ????????//?接收A.vue傳遞過來的數(shù)據(jù)
          ????????inject('info')??//?{name:?'前端印象',?age:?22}
          ????}
          }
          script>

          (12)watch && watchEffect

          watchwatchEffect 都是用來監(jiān)視某項數(shù)據(jù)變化從而執(zhí)行指定的操作的,但用法上還是有所區(qū)別

          watch:watch( source, cb, [options] )

          參數(shù)說明:

          • source:可以是表達式或函數(shù),用于指定監(jiān)聽的依賴對象
          • cb:依賴對象變化后執(zhí)行的回調(diào)函數(shù)
          • options:可參數(shù),可以配置的屬性有 immediate(立即觸發(fā)回調(diào)函數(shù))、deep(深度監(jiān)聽)

          當監(jiān)聽 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>

          當監(jiān)聽 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>

          當同時監(jiān)聽多個值時:

          <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 方法的第一個參數(shù)我們已經(jīng)指定了監(jiān)聽的對象,因此當組件初始化時,不會執(zhí)行第二個參數(shù)中的回調(diào)函數(shù),若我們想讓其初始化時就先執(zhí)行一遍,可以在第三個參數(shù)對象中設置 immediate: true

          watch 方法默認是漸層的監(jiān)聽我們指定的數(shù)據(jù),例如如果監(jiān)聽的數(shù)據(jù)有多層嵌套,深層的數(shù)據(jù)變化不會觸發(fā)監(jiān)聽的回調(diào),若我們想要其對深層數(shù)據(jù)也進行監(jiān)聽,可以在第三個參數(shù)對象中設置 deep: true

          補充: watch方法會返回一個stop方法,若想要停止監(jiān)聽,便可直接執(zhí)行該stop函數(shù)

          接下來再來聊聊 watchEffect,它與 watch 的區(qū)別主要有以下幾點:

          1. 不需要手動傳入依賴
          2. 每次初始化時會執(zhí)行一次回調(diào)函數(shù)來自動獲取依賴
          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秒后打?。?br>??????????????????1
          ??????????????????ls
          ??????????*/

          ??????????})

          ??????????setTimeout(()?=>?{
          ????????????state.count?++
          ????????????state.name?=?'ls'
          ??????????},?1000)
          ????}
          }
          script>

          從上述代碼中可以看出,我們并沒有像 watch 方法一樣先給其傳入一個依賴,而是直接指定了一個回調(diào)函數(shù)

          當組件初始化時,將該回調(diào)函數(shù)執(zhí)行一次,自動獲取到需要檢測的數(shù)據(jù)是 state.countstate.name

          根據(jù)以上特征,我們可以自行選擇使用哪一個監(jiān)聽器

          (13)getCurrentInstance

          我們都知道在Vue2的任何一個組件中想要獲取當前組件的實例可以通過 this 來得到,而在Vue3中我們大量的代碼都在 setup 函數(shù)中運行,并且在該函數(shù)中 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>

          我們來看一下其打印結果

          因為 instance 包含的內(nèi)容太多,所以沒截完整,但是主要的內(nèi)容都在圖上了,我們重點來看一下 ctxproxy,因為這兩個才是我們想要的 this 的內(nèi)容

          可以看到 ctxproxy 的內(nèi)容十分類似,只是后者相對于前者外部包裝了一層 proxy,由此可說明 proxy 是響應式的

          (14)useStore

          在Vue2中使用 Vuex,我們都是通過 this.$store 來與獲取到Vuex實例,但上一部分說了原本Vue2中的 this 的獲取方式不一樣了,并且我們在Vue3的 getCurrentInstance().ctx 中也沒有發(fā)現(xiàn) $store 這個屬性,那么如何獲取到Vuex實例呢?這就要通過 vuex 中的一個方法了,即 useStore

          //?store?文件夾下的?index.js
          import?Vuex?from?'vuex'

          const?store?=?Vuex.createStore({
          ????state:?{
          ??????name:?'前端印象',
          ??????age:?22
          ????},
          ????mutations:?{
          ??????……
          ????},
          ????……
          })

          //?example.vue
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    人人擦人人 | 亚洲国产精品毛片在线看 | 国产黄色影片免费 | 日本精品一区二区三区视频 | 欧美精品A |