最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3響應式API之ref的使用

 更新時間:2023年10月24日 15:10:16   作者:前端不加班  
這篇文章主要介紹了vue3響應式API之ref的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

vue3響應式API之ref使用

ref 是最常用的一個響應式 API,它可以用來定義所有類型的數(shù)據(jù),包括 Node 節(jié)點和組件。

沒錯,在 Vue 2 常用的 this.$refs.xxx 來取代 document.querySelector(‘.xxx’) 獲取 Node 節(jié)點的方式,也是使用這個 API 來取代。

類型聲明

在開始使用 API 之前,需要先了解在 TypeScript 中如何聲明 Ref 變量的類型。 

API 本身的類型

先看 API 本身, ref API 是一個函數(shù),通過接受一個泛型入?yún)?,返回一個響應式對象,所有的值都通過 .value 屬性獲取,這是 API 本身的 TS 類型:

// `ref` API 的 TS 類型
function ref<T>(value: T): Ref<UnwrapRef<T>>

// `ref` API 的返回值的 TS 類型
interface Ref<T> {
  value: T
}

因此在聲明變量時,是使用尖括號 <> 包裹其 TS 類型,緊跟在 ref API 之后:

// 顯式指定 `msg.value` 是 `string` 類型
const msg=ref<string>('hello')

再回看該 API 本身的類型,其中使用了 T 泛型,這表示在傳入函數(shù)的入?yún)r,可以不需要手動指定其 TS 類型, TypeScript 會根據(jù)這個 API 所返回的響應式對象的 .value 屬性的類型,確定當前變量的類型。

因此也可以省略顯式的類型指定,像下面這樣聲明變量,其類型交給 TypeScript 去自動推導:

// TypeScript 會推導 `msg.value` 是 `string` 類型
const msg = ref('Hello World')

對于聲明時會賦予初始值,并且在使用過程中不會改變其類型的變量,是可以省略類型的顯式指定的。

而如果有顯式的指定的類型,那么在一些特殊情況下,初始化時可以不必賦值,這樣 TypeScript 會自動添加 undefined 類型:

const msg = ref<string>()
console.log(msg.value) // undefined

msg.value = 'Hello World!'
console.log(msg.value) // Hello World!

因為入?yún)⒘艨諘r,雖然指定了 string 類型,但實際上此時的值是 undefined ,因此實際上這個時候的 msg.value 是一個 string | undefined 的聯(lián)合類型。

對于聲明時不知道是什么值,在某種條件下才進行初始化的情況,就可以省略其初始值,但是切記在調用該變量的時候對 .value 值進行有效性判斷。

而如果既不顯式指定類型,也不賦予初始值,那么會被默認為 any 類型,除非真的無法確認類型,否則不建議這么做。 

API 返回值的類型

細心的開發(fā)者還會留意到 ref API 類型里面還標注了一個返回值的 TS 類型:

interface Ref<T> {
  value: T
}

它是代表整個 Ref 變量的完整類型:

上文聲明 Ref 變量時,提到的 string 類型都是指 msg.value 這個 .value 屬性的類型

而 msg 這個響應式變量,其本身是 Ref 類型

如果在開發(fā)過程中需要在函數(shù)里返回一個 Ref 變量,那么其 TypeScript 類型就可以這樣寫(請留意 Calculator 里的 num 變量的類型):

// 導入 `ref` API
import { ref } from 'vue'
// 導入 `ref` API 的返回值類型
import type { Ref } from 'vue'

// 聲明 `useCalculator` 函數(shù)的返回值類型
interface Calculator {
  // 這里包含了一個 Ref 變量
  num: Ref<number>
  add: () => void
}

// 聲明一個 “使用計算器” 的函數(shù)
function useCalculator(): Calculator {
  const num = ref<number>(0)

  function add() {
    num.value++
  }

  return {
    num,
    add,
  }
}

// 在執(zhí)行使用計算器函數(shù)時,可以獲取到一個 Ref 變量和其他方法
const { num, add } = useCalculator()
add()
console.log(num.value) // 1

上面這個簡單的例子演示了如何手動指定 Ref 變量的類型,對于邏輯復用時的函數(shù)代碼抽離、插件開發(fā)等場景非常有用!

當然大部分情況下可以交給 TypeScript 自動推導,但掌握其用法,在必要的時候就派得上用場了!

變量的定義

在了解了如何對 Ref 變量進行類型聲明之后,面對不同的數(shù)據(jù)類型,相信都得心應手了!

但不同類型的值之間還是有少許差異和注意事項,例如上文提及到該 API 可以用來定義所有類型的數(shù)據(jù),包括 Node 節(jié)點和組件,具體可以參考下文的示例。

基本類型

對字符串、布爾值等基本類型的定義方式,比較簡單:

//字符串
const msg = ref<string>('123')
//數(shù)值
const count =ref<number>(1)
//布爾值
const isVip = ref<boolean>(false)

引用類型

對于對象、數(shù)組等引用類型也適用,比如要定義一個對象:

// 先聲明對象的格式
interface Member {
  id: number
  name: string
}

// 在定義對象時指定該類型
const userInfo = ref<Member>({
  id: 1,
  name: 'Tom',
})

定義一個普通數(shù)組:

const uids =ref<number[]>([1,2,3])
//字符串數(shù)組
const names = ref<string[]>(['Tom', 'Petter', 'Andy'])

定義一個對象數(shù)組:

//聲明對象的格式
interface Member{
  id:number
  name:string
}
//定義一個對象數(shù)組
const memberList = ref<Member[]>([
	{
	    id: 1,
	    name: 'Tom',
	  },
	  {
	    id: 2,
	    name: 'Petter',
	  },
])

DOM 元素與子組件

除了可以定義數(shù)據(jù),ref 也有熟悉的用途,就是用來掛載節(jié)點,也可以掛在子組件上,也就是對應在 Vue 2 時常用的 this.$refs.xxx 獲取 DOM 元素信息的作用。

模板部分依然是熟悉的用法,在要引用的 DOM 上添加一個 ref 屬性:

<template>
  <!-- 給 DOM 元素添加 `ref` 屬性 -->
  <p ref="msg">請留意該節(jié)點,有一個 ref 屬性</p>

  <!-- 子組件也是同樣的方式添加 -->
  <Child ref="child" />
</template>

在 代碼里添加的 ref 屬性的值,是對應

請保證視圖渲染完畢后再執(zhí)行 DOM 或組件的相關操作(需要放到生命周期的 onMounted 或者 nextTick 函數(shù)里,這一點在 Vue 2 也是一樣);

該 Ref 變量必須 return 出去才可以給到 使用,這一點是 Vue 3 生命周期的硬性要求,子組件的數(shù)據(jù)和方法如果要給父組件操作,也要 return 出來才可以。

配合上面的 ,來看看

import { defineComponent, onMounted, ref } from 'vue'
import Child from '@cp/Child.vue'

export default defineComponent({
  components: {
    Child,
  },
  setup() {
    // 定義掛載節(jié)點,聲明的類型詳見下方附表
    const msg = ref<HTMLElement>()
    const child = ref<typeof Child>()

    // 請保證視圖渲染完畢后再執(zhí)行節(jié)點操作 e.g. `onMounted` / `nextTick`
    onMounted(() => {
      // 比如獲取 DOM 的文本
      console.log(msg.value.innerText)

      // 或者操作子組件里的數(shù)據(jù)
      child.value.isShowDialog = true
    })

    // 必須 `return` 出去才可以給到 `<template />` 使用
    return {
      msg,
      child,
    }
  },
})

關于 DOM 和子組件的 TS 類型聲明,可參考以下規(guī)則:

另外,關于這一小節(jié),有一個可能會引起 TS 編譯報錯的情況是,一些腳手架創(chuàng)建出來的項目會默認啟用 --strictNullChecks 選項,會導致案例中的代碼無法正常編譯,出現(xiàn)如下報錯:

? npm run build

hello-vue3@0.0.0 build
vue-tsc --noEmit && vite build

src/views/home.vue:27:7 - error TS2532: Object is possibly 'undefined'.

27       child.value.isShowDialog = true
         ~~~~~~~~~~~


Found 1 error in src/views/home.vue:27

這是因為在默認情況下 null 和 undefined 是所有類型的子類型,但開啟了 strictNullChecks 選項之后,會使 null 和 undefined 只能賦值給 void 和它們各自,這是一個更為嚴謹?shù)倪x項,可以保障程序代碼的健壯性,但對于剛接觸 TypeScript 不久的開發(fā)者可能不太友好。

有以下幾種解決方案可以參考:

在涉及到相關操作的時候,對節(jié)點變量增加一個判斷:

// 添加 `if` 分支,判斷 `.value` 存在時才執(zhí)行相關代碼
if (child.value) {
  // 讀取子組件的數(shù)據(jù)
  console.log(child.value.num)

  // 執(zhí)行子組件的方法
  child.value.sayHi('Use `if` in `onMounted` API.')
}

通過 TS 的可選符 ? 將目標設置為可選,避免出現(xiàn)錯誤(這個方式不能直接修改子組件數(shù)據(jù)的值):

// 讀取子組件的數(shù)據(jù)(留意 `.num` 前面有一個 `?` 問號)
console.log(child.value?.num)

// 執(zhí)行子組件的方法(留意 `.sayHi` 前面有一個 `?` 問號)
child.value?.sayHi('use ? in onMounted')

在項目根目錄下的 tsconfig.json 文件里,顯式的關閉 strictNullChecks 選項,關閉后,需要開發(fā)者在寫代碼的時候,自行把控好是否需要對 null 和 undefined 進行判斷

{
  "compilerOptions": {
    // ...
    "strictNullChecks": false
  }
  // ...
}

使用 any 類型代替,但是寫 TypeScript 還是盡量不要使用 any ,滿屏的 AnyScript 不如直接使用 JavaScript

變量的讀取與賦值

前面在介紹 API 類型的時候已經(jīng)了解,通過 ref 聲明的變量會全部變成對象,不管定義的是什么類型的值,都會轉化為一個 Ref 對象,其中 Ref 對象具有指向內(nèi)部值的單個 Property .value。

也就是說,任何 Ref 對象的值都必須通過 xxx.value 才可以正確獲取。

請牢記上面這句話,初擁 Vue 3 的開發(fā)者很多 BUG 都是由于這個問題引起的(包括筆者剛開始使用 Vue 3 的那段時間,嘿嘿)。

讀取變量

平時對于普通變量的值,讀取的時候都是直接調用其變量名即可:

// 讀取一個字符串
const msg: string = 'Hello World!'
console.log(msg)

// 讀取一個數(shù)組
const uids: number[] = [1, 2, 3]
console.log(uids[1])

而 Ref 對象的值的讀取,切記!必須通過 .value !

// 讀取一個字符串
const msg = ref<string>('Hello World!')
console.log(msg.value)

// 讀取一個數(shù)組
const uids = ref<number[]>([1, 2, 3])
console.log(uids.value[1])

為變量賦值

普通變量需要使用 let 聲明才可以修改其值,由于 Ref 對象是個引用類型,所以可以使用 const 聲明,直接通過 .value 修改。

// 聲明一個字符串變量
const msg = ref<string>('Hi!')

// 等待 1s 后修改它的值
setTimeout(() => {
  msg.value = 'Hello!'
}, 1000)

因此日常業(yè)務中,像在對接服務端 API 的接口數(shù)據(jù)時,可以自由的使用 forEach、map、filter 等方法操作 Ref 數(shù)組,或者直接重置它,而不必擔心數(shù)據(jù)失去響應性。

const data = ref<string[]>([])

// 提取接口的數(shù)據(jù)
data.value = api.data.map((item: any) => item.text)

// 重置數(shù)組
data.value = []

為什么突然要說這個呢?因為涉及到下一部分的知識,關于 reactive API 在使用上的注意事項。

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • vue關于select組件綁定的值為數(shù)字類型的問題

    vue關于select組件綁定的值為數(shù)字類型的問題

    這篇文章主要介紹了vue關于select組件綁定的值為數(shù)字類型的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue 中 beforeRouteEnter 死循環(huán)的問題

    vue 中 beforeRouteEnter 死循環(huán)的問題

    這篇文章主要介紹了vue beforeRouteEnter 死循環(huán)的問題,在文章末尾給大家補充介紹了vue中beforeRouteEnter使用的誤區(qū),需要的朋友可以參考下
    2019-04-04
  • vue判斷內(nèi)容是否滑動到底部的三種方式

    vue判斷內(nèi)容是否滑動到底部的三種方式

    這篇文章主要介紹了vue判斷內(nèi)容是否滑動到底部的三種方式,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-04-04
  • vue實現(xiàn)點擊追加選中樣式效果

    vue實現(xiàn)點擊追加選中樣式效果

    今天小編就為大家分享一篇vue實現(xiàn)點擊追加選中樣式效果,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • vue中的config目錄下index.js解讀

    vue中的config目錄下index.js解讀

    這篇文章主要介紹了vue中的config目錄下index.js解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • VUE 解決mode為history頁面為空白的問題

    VUE 解決mode為history頁面為空白的問題

    今天小編就為大家分享一篇VUE 解決mode為history頁面為空白的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • vue.js刪除列表中的一行

    vue.js刪除列表中的一行

    這篇文章給大家分享了vue.js刪除列表中的一行的實例操作以及代碼分享,有興趣的朋友參考下。
    2018-06-06
  • 淺談Vue3.0新版API之composition-api入坑指南

    淺談Vue3.0新版API之composition-api入坑指南

    這篇文章主要介紹了Vue3.0新版API之composition-api入坑指南,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • Vue學習筆記之跨域的6種解決方案

    Vue學習筆記之跨域的6種解決方案

    在前后端分離項目中,跨域是一定會出現(xiàn)的問題,下面這篇文章主要給大家介紹了關于Vue學習筆記之跨域的6種解決方案,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • vue watch監(jiān)聽數(shù)據(jù)變化的案例詳解

    vue watch監(jiān)聽數(shù)據(jù)變化的案例詳解

    監(jiān)聽數(shù)據(jù)變化,在Vue中是通過偵聽器來實現(xiàn)的,你也可以將它理解為監(jiān)聽器,時刻監(jiān)聽某個數(shù)據(jù)的變化,本文將通過代碼示例為大家詳細的介紹一下vue watch如何監(jiān)聽數(shù)據(jù)變化,需要的朋友可以參考下
    2023-07-07

最新評論

宽城| 五寨县| 新密市| 阿克苏市| 玉龙| 久治县| 紫阳县| 永昌县| 岗巴县| 黔西县| 上林县| 金门县| 镇江市| 二手房| 雷波县| 伊川县| 塘沽区| 黄陵县| 应城市| 辽阳县| 台北县| 沾益县| 铜鼓县| 黎城县| 忻城县| 赤城县| 泸溪县| 石家庄市| 洪雅县| 开化县| 扎囊县| 涟源市| 静海县| 慈溪市| 全州县| 高雄县| 彭山县| 宜君县| 运城市| 文登市| 武隆县|