VUE3快速上手及常用API函數彙總!

2022-03-24 10:00:07

Vue3簡介

  • 2020年9月18日,Vue.js釋出3.0版本,代號:One Piece(海賊王)
  • 耗時2年多、2600+次提交、30+個RFC、600+次PR、99位貢獻者
  • github上的tags地址(https://github.com/vuejs/vue-next/releases/tag/v3.0.0)

Vue3帶來了什麼?

效能的提升

  • 打包大小減少41%
  • 初次渲染快55%,更新渲染快133%
  • 記憶體減少54%

原始碼的升級

  • 使用Proxy代替defineProperty實現響應式
  • 重寫虛擬DOM的實現和Tree-Shaking

擁抱TypeScript

  • Vue3可以更好的支援TypeScript

新的特性

  • Composition API(組合API)

    • setup設定
    • ref與reactive
    • watch與watchEffect
    • provide與inject
  • 新的內建元件

    • Fragment
    • Teleport
    • Suspense
  • 其他改變

    • 新的生命週期勾點
    • data選項應始終被宣告為一個函數
    • 移除keyCode支援作為v-on的修飾符

相關推薦:《》

一、建立Vue3.0工程

1.使用 vue-cli 建立

官方檔案:https://cli.vuejs.org/zh/guide/creating-a-project.html

## 檢視@vue/cli版本,確保@vue/cli版本在4.5.0以上
vue --version

## 安裝或者升級你的@vue/cli
npm install -g @vue/cli

## 建立
vue create vue_test

## 啟動
cd vue_test
npm run serve

2.使用 vite 建立

Vite 官方中文檔案:https://cn.vitejs.dev

  • 什麼是vite?新一代前端構建工具
  • 優勢如下:
    • 開發環境中,無需打包操作,可快速地冷啟動
    • 輕量快速的熱過載(HMR)
    • 真正的按需編譯,不再等待整個應用編譯完成

傳統構建與vite構建對比圖:

ea5206e0badc5d7c5198a328c1e502d.png

69db93b1b79ef245bd120e109dd85e2.png

## 建立工程
npm init vite-app <project-name>

## 進入工程目錄
cd <project-name>

## 安裝依賴
npm install

## 執行
npm run dev

二、常用 Composition API

官方檔案:https://v3.cn.vuejs.org/guide/composition-api-introduction.html

1.拉開序幕的setup

  • 理解:Vue3.0中一個新的設定項,值為一個函數。
  • setup是所有Composition API(組合API)「表演的舞臺」。
  • 元件中所用到的:資料、方法等,均要設定在setup中。
  • setup函數的兩種返回值:
    • 若返回一個物件,則物件中的屬性、方法,在模板中均可以直接使用。(重點關注!)
    • 若返回一個渲染函數,則可以自定義渲染內容。(瞭解即可)
  • 注意點:
    • 儘量不要與Vue2.x設定混用。
      • Vue2.x設定(data、methods、computed…)中可以存取到setup中的屬性、方法。
      • 但在setup中不能存取到Vue2.x的設定(data、methods、computed…)。
      • 如果有重名,則報錯。
    • setup不能是一個async函數,因為返回值不再是return的物件,而是Promise,模板看不到return物件中的屬性。(後期也可以返回一個Promise範例,但需要Suspense和非同步元件的配合)

2.ref函數

  • 作用:定義一個響應式的資料
  • 引入:import {ref} from "vue"
  • 語法:const xxx = ref(initValue)
    • 建立一個包含響應式資料的參照物件(reference物件,簡稱ref物件)
    • JS中運算元據:xxx.value
    • 模板中讀取資料,不需要.value,直接<p>{{xxx}}</p>
  • 備註:
    • 接收的資料可以是基本型別,也可以是物件型別
    • 基本型別的資料:響應式依然是靠Object.defineProperty()getset完成的
    • 物件型別的資料:內部「求助」了Vue3.0中的一個新函數——reactive函數

3.reactive函數

  • 作用:定義一個物件型別的響應式資料(基本型別不要用它,要用ref函數)
  • 引入:import {reactive} from 'vue'
  • 語法:const 代理物件 = reactive(源物件)接收一個物件(或陣列),返回一個代理物件(Proxy的範例物件,簡稱proxy物件)
  • reactive定義的響應式資料是「深層次的」
  • 內部基於 ES6 的 Proxy 實現,通過代理物件操作源物件內部資料進行操作

4.Vue3.0中的響應式原理

Vue2.x的響應式

  • 實現原理:
    • 物件型別:通過Object.defineProperty()對屬性的讀取、修改進行攔截(資料劫持)
    • 陣列型別:通過重寫更新陣列的一系列方法來實現攔截(對陣列的變更方法進行了包裹)
Object.defineProperty(data, 'count', {
    get() {},
    set() {}})
  • 存在問題:
    • 新增屬性、刪除屬性,介面不會更新
    • 直接通過下標修改陣列,介面不會自動更新

Vue3.0的響應式

  • 實現原理:
    • 通過Proxy(代理):攔截物件中任意屬性的變化,包括:屬性值的讀寫、屬性的新增、屬性的刪除等
    • 通過Reflect(反射):對源物件的屬性進行操作
    • MDN檔案中描述的Proxy與Reflect
new Proxy(data, {
    // 攔截讀取屬性值
    get(target, prop) {
        return Reflect.get(target, prop)
    },
    // 攔截設定屬性值或新增新屬性
    set(target, prop, value) {
        return Reflect.set(target, prop, value)
    },
    // 攔截刪除屬性
    deleteProperty(target, prop) {
        return Reflect.deleteProperty(target, prop)
    }})proxy.name = 'tom'

5.reactive對比ref

  • 從定義資料角度對比:
    • ref用來定義:基本型別資料
    • reactive用來定義:物件(或陣列)型別資料
    • 備註:ref也可以用來定義物件(或陣列)型別資料,它內部會自動通過reactive轉為代理物件
  • 從原理角度對比:
    • ref通過Object.defineProperty()getset來實現響應式(資料劫持)
    • reactive通過使用Proxy來實現響應式(資料劫持),並通過Reflect操作源物件內部的資料
  • 從使用角度對比:
    • ref定義的資料:運算元據需要.value,讀取資料時模板中直接讀取不需要.value
    • reactive定義的資料:運算元據與讀取資料均不需要.value

6.setup的兩個注意點

  • setup執行的時機

    • 在beforeCreate之前執行一次,this是undefined
  • setup的引數

    • props:值為物件,包含:元件外部傳遞過來,且元件內部宣告接收了的屬性
    • context:上下文物件
      • attrs(撿漏props):值為物件,包含:元件外部傳遞過來,但沒有在props設定中宣告的屬性,相當於Vue2中的this.$attrs
      • slots:收到的插槽內容,相當於Vue2中的this.$slots
      • emit:分發自定義事件的函數,相當於Vue2中的this.$emit

7.計算屬性與監視

computed函數

  • 與Vue2.x中computed設定功能一致
  • 寫法:
import {
    computed} from 'vue'setup() {
    ...
    // 計算屬性——簡寫
    let fullName = computed(() => {
        return person.firstName + '-' + person.lastName    })
    // 計算屬性——完整
    let fullName = computed({
        get() {
            return person.firstName + '-' + person.lastName        },
        set(value) {
            const nameArr = value.split('-')
            person.firstName = nameArr[0]
            person.lastName = nameArr[1]
        }
    })}

watch函數

  • 與Vue2.x中watch設定功能一致
  • 兩個小「坑」:
    • 監視reactive定義的響應式資料時:oldValue無法正確獲取、強制開啟了深度監視(deep設定失效)
    • 監視reactive定義的響應式資料中某個屬性時:deep設定有效
// 情況一:監視ref定義的響應式資料
watch(sum, (newValue, oldValue) => {
    console.log('sum變化了', newValue, oldValue)
}, {
    immediate: true
})

// 情況二:監視多個ref定義的響應式資料
watch([sum, msg], (newValue, oldValue) => {
    console.log('sum或msg變化了', newValue, oldValue)
})

/*
情況三:監視reactive定義的響應式資料
若watch監視的是reactive定義的響應式資料,則無法正確獲得oldValue
若watch監視的是reactive定義的響應式資料,則強制開啟了深度監視
*/
watch(person, (newValue, oldValue) => {
    console.log('person變化了', newValue, oldValue)
}, {
    immediate: true,
    deep: false
}) // 此處的deep設定不再奏效

// 情況四:監視reactive定義的響應式資料中的某個屬性
watch(() => person.job, (newValue, oldValue) => {
    console.log('person的job變化了', newValue, oldValue)
}, {
    immediate: true,
    deep: true
})

// 情況五:監視reactive定義的響應式資料中的某些屬性
watch([() => person.job, () => person.name], (newValue, oldValue) => {
    console.log('person的job變化了', newValue, oldValue)
}, {
    immediate: true,
    deep: true
})

// 特殊情況
watch(() => person.job, (newValue, oldValue) => {
    console.log('person的job變化了', newValue, oldValue)
}, {
    deep: true
}) // 此處由於監視的是reactive所定義的物件中的某個屬性,所以deep設定有效

watchEffect函數

  • watch的套路是:既要指明監視的屬性,也要指明監視的回撥
  • watchEffect的套路是:不用指明監視哪個屬性,監視的回撥中用到哪個屬性,那就監視哪個屬性
  • watchEffect有點像computed:
    • 但computed注重的計算出來的值(回撥函數的返回值),所以必須要寫返回值
    • 而watchEffect更注重的是過程(回撥函數的函數體),所以不用寫返回值
// watchEffect所指定的回撥中用到的資料只要發生變化,則直接重新執行回撥
watchEffect(() => {
    const x1 = sum.value
    const x2 = person.age
    console.log('watchEffect設定的回撥執行了')
})

8.生命週期

Vue2.x的生命週期:
Vue2.x的生命週期
Vue3.0的生命週期:

  • Vue3.0中可以繼續使用Vue2.x中的生命週期勾點,但有兩個被更名:
    • beforeDestroy改名為beforeUnmount
    • destroyed改名為unmounted
  • Vue3.0也提供了 Composition API 形式的生命週期勾點,與Vue2.x中勾點對應關係如下:
    • beforeCreate===>setup()
    • created===>setup()
    • beforeMount===>onBeforeMount
    • mounted===>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated===>onUpdated
    • beforeUnmount===>onBeforeUnmount
    • unmounted===>onUnmounted

9.自定義hook函數

  • 什麼是hook?——本質是一個函數,把setup函數中使用的Composition API進行了封裝
  • 類似於Vue2.x中的mixin
  • 自定義hook的優勢:複用程式碼,讓setup中的邏輯更清楚易懂

10.toRef

  • 作用:建立一個 ref 物件,其 value 值指向另一個物件中的某個屬性
  • 語法:const name = toRef(person, 'name')
  • 應用:要將響應式物件中的某個屬性單獨提供給外部使用,並且還不會丟失響應式的時候
  • 擴充套件:toRefstoRef功能一致,但可以批次建立多個 ref 物件,語法:toRefs(person)

三、其它 Composition API

1.shallowReactive 與 shallowRef

  • shallowReactive:只處理物件最外層屬性的響應式(淺響應式)
  • shallowRef:只處理基本資料型別的響應式,不進行物件的響應式處理
  • 什麼時候使用?
    • 如果有一個物件資料,結構比較深,但變化時只是外層屬性變化 ===> shallowReactive
    • 如果有一個物件資料,後續功能不會修改該物件中的屬性,而是生新的物件來替換 ===> shallowRef

2.readonly 與 shallowReadonly

  • readonly:讓一個響應式資料變為唯讀的(深唯讀)
  • shallowReadonly:讓一個響應式資料變為唯讀的(淺唯讀)
  • 應用場景:不希望資料被修改時

3.toRaw 與 markRaw

  • toRaw:
    • 作用:將一個由reactive生成的響應式物件轉為普通物件
    • 使用場景:用於讀取響應式物件對應的普通物件,對這個普通物件的所有操作,不會引起頁面更新
  • markRaw:
    • 作用:標記一個物件,使其永遠不會再成為響應式物件
    • 應用場景:
      • 有些值不應被設定為響應式的,例如複雜的第三方類庫等
      • 當渲染具有不可變資料來源的大列表時,跳過響應式轉換可以提高效能

4.customRef

  • 作用:建立一個自定義的ref,並對其依賴項跟蹤和更新觸發進行顯式控制
  • 實現防抖效果:
<template>
    <input type="text" v-model="keyword">
    <h3>{{keyword}}</h3>
</template>

<script>
import {
    ref,
    customRef
} from 'vue'
export default {
    name: 'Demo',
    setup() {
        // let keyword = ref('hello') //使用Vue準備好的內建ref
        // 自定義一個myRef
        function myRef(value, delay) {
            let timer
            // 通過customRef去實現自定義
            return customRef((track, trigger) => {
                return {
                    get() {
                        track() // 告訴Vue這個value值是需要被「追蹤」的
                        return value
                    },
                    set(newValue) {
                        clearTimeout(timer)
                        timer = setTimeout(() => {
                            value = newValue
                            trigger() // 告訴Vue去更新介面
                        }, delay)
                    }
                }
            })
        }
        let keyword = myRef('hello', 500) // 使用程式設計師自定義的ref
        return {
            keyword
        }
    }
}
</script>

5.provide 與 inject

28da193f6d45be8cd5e3f558bb5b5fc.png

  • 作用:實現祖先元件與後代元件間通訊
  • 套路:祖先元件有一個provide選項來提供資料,後代元件有一個inject選項來開始使用這些資料
  • 具體寫法:

祖先元件中:

setup() {
    ......
    let car = reactive({
        name: '賓士',
        price: '40萬'
    })
    provide('car', car)
    ......}

後代元件中:

setup(props, context) {
    ......
    const car = inject('car')
    return {
        car    }
    ......}

6.響應式資料的判斷

  • isRef:檢查一個值是否為一個 ref 物件
  • isReactive:檢查一個物件是否是由reactive建立的響應式代理
  • isReadonly:檢查一個物件是否是由readonly建立的唯讀代理
  • isProxy:檢查一個物件是否是由reactive或者readonly方法建立的代理

四、Composition API 的優勢

1.Options API 存在的問題

使用傳統OptionsAPI中,新增或者修改一個需求,就需要分別在data,methods,computed裡修改。

2.Composition API 的優勢

我們可以更加優雅地組織我們的程式碼、函數,讓相關功能的程式碼更加有序地組織在一起。

五、新的元件

1.Fragment

  • 在Vue2中,元件必須有一個根標籤
  • 在Vue3中,元件可以沒有根標籤,內部會將多個標籤包含在一個Fragment虛擬元素中
  • 好處:減少標籤層級,減小記憶體佔用

2.Teleport

  • 什麼是Teleport?——Teleport是一種能夠將我們的元件html結構移動到指定位置的技術
<teleport to="移動位置">
    <div v-if="isShow" class="mask">
        <div class="dialog">
            <h3>我是一個彈窗</h3>
            <button @click="isShow = false">關閉彈窗</button>
        </div>
    </div>
</teleport>

3.Suspense

  • 等待非同步元件時渲染一些額外內容,讓應用有更好的使用者體驗
  • 使用步驟:

非同步引入元件:

import {
    defineAsyncComponent
} from 'vue'
const Child = defineAsyncComponent(() => import('./components/Child.vue'))

使用Suspense包裹元件,並設定好defaultfallback

<template>
    <div class="app">
        <h3>我是App元件</h3>
        <Suspense>
            <template v-slot:default>
                <Child />
            </template>
            <template v-slot:fallback>
                <h3>載入中...</h3>
            </template>
        </Suspense>
    </div>
</template>

六、其他

1.全域性API的轉移

  • Vue2.x有許多全域性API和設定
    • 例如:註冊全域性元件、註冊全域性指令等
// 註冊全域性元件
Vue.component('MyButton', {
    data: () => ({
        count: 0
    }),
    template: '<button @click="count++">Clicked {{ count }} times.</button>'
})

// 註冊全域性指令
Vue.directive('focus', {
    inserted: el => el.focus()
})
  • Vue3.0中對這些API做出了調整
    • 將全域性的API,即:Vue.xxx調整到應用範例(app)上
2.x全域性API(Vue3.x範例API(app
Vue.config.xxxapp.config.xxx
Vue.config.productionTip移除
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.prototypeapp.config.globalProperties

2.其他改變

  • data選項應始終被宣告為一個函數
  • 過渡動畫類名的更改:

Vue2.x寫法:

.v-enter,
.v-leave-to {
    opacity: 0;}.v-leave,
.v-enter-to {
    opacity: 1;}

Vue3.x寫法:

.v-enter-from,
.v-leave-to {
    opacity: 0;}.v-leave-from,
.v-enter-to {
    opacity: 1;}
  • 移除keyCode作為v-on的修飾符,同時也不再支援Vue.config.keyCodes.xxx(按鍵別名)
  • 移除v-on.native修飾符

父元件中繫結事件:

<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent" />

子元件中宣告自定義事件:

<script>
    export default {
        emits: ['close'] // 這裡宣告的事件才算作自定義事件,所以在父元件中click是原生事件
    }
</script>
  • 移除過濾器filter
    過濾器雖然看起來很方便,但它需要一個自定義語法,打破大括號內表示式「只是JavaScript」的假設,這不僅有學習成本,而且有實現成本,建議用方法呼叫或計算屬性去替代過濾器

以上就是VUE3快速上手及常用API函數彙總!的詳細內容,更多請關注TW511.COM其它相關文章!