【Vuejs】1058- 盤點 Vue3 那些有趣的 API

從開始的Vue到Vue2再到現在的Vue3,前端開發人員一直被迫營業,永遠也追不上尤大大寫代碼的腳步👣 。

今天我們放慢追趕的腳步,一起來看看尤大大在Vue3書寫了哪些有趣的API,有些可能說不上哪裏有趣,但是看起來就是比之前舒服一些(強迫症在線發作...)。文末有尤大大連夜寫的新需求

data選項哪去了?

回想我們在Vue2中創建響應式數據是這樣的:

...
data() {
  return {
    num:1  
  }
}
...

而Vue3會 setup 組合式API這個選項了,爲此引入了refreactive等響應式API,來看看怎麼寫的吧:

<template>
  <div>num:{{num}}</div>
  <div>refNum:{{refNum}}</div>
  <div>state對象:名字:{{state.name}},年齡:{{state.age}}</div>
</template>

<script>
import { defineComponent, reactive, ref } from "vue"
export default defineComponent({
  setup() {
    const num = 1  /
/不具備響應式
    const refNum = ref(2)
    const state = reactive({
      name: '小黃',
      age: 18
    })
    return {
      num,
      refNum,
      state
    }
  }
})
</
script>

你可以看到Vue2的data選項已經被ref、reactive這樣的API給替換了。

那麼在setup如何對ref、reactive聲明的數據修改操作呢?

...
setup() {
  const count = ref(1)
  console.log(count.value) // => 1
  count.value++
  console.log(count.value) // => 2

  const str = ref('小黃')
  console.log(str.value) // => 小黃
}
...

可以看到使用 ref 聲明的數據可以直接使用 .value 這種形式更新數據。但是你也許會疑問爲什麼在<tempalte></template>視圖中爲什麼不需要 .value ,其實是vue內部做了操作。另外,打印一下可以看到ref聲明數據:

reactive 也是響應式的聲明,它是返回對象的響應式副本

...
setup() {
  const state = reactive({
    name'小黃',
    age18
  })
  console.log(state) // =>
}
...

我們直接打印下state對象,它其實是一個Proxy對象:

...
setup() {
  console.log(state.name) // => 小黃
  console.log(state.age) // => 18
  //對數據更改
  setTimeout(() => {
    state.age = 20
    console.log(state.age) // => 20
  }, 1000)
}
...

也許你已經注意到了開頭舉的例子——所有聲明的變量都被 return 出去了,這看起來有什麼好處呢?

  • 可以更加清晰得知道,數據與視圖之前的關係。setup裏對數據操作,視圖渲染return出來的數據
  • 更好的保護組件獨有的數據,不需要暴露給視圖的數據我就不寫在return裏中

再者,你可能會討厭爲什麼通過 reactive 聲明的數據在視圖中使用的時候又要 xx.屬性名 的方式纔行,有辦法不寫嗎?有!尤大大滿足開發者的一切便捷編碼習慣。toRefs 就出來了,在結合ES9的擴展運算符 ... 就可以滿足要求了👏👏👏

<template>
  //這裏不再需要state包裹了,屬性已經被展開return出來了
  <div>state對象:名字:{{name}},年齡:{{age}}</div>
</template>

<script>
import {defineComponent, reactive, toRefs } from "vue"
export default defineComponent({
  setup() {
    const state = reactive({
      name: '小黃',
      age: 18
    })
    return {
      ...toRefs(state)
    }
  }
})
</
script>

computed計算屬性更好看了?

計算屬性在使用上好像變得更加令人愉快了,先來看Vue2的寫法吧

...
data(){
  return {
    str:'小黃'
  }
},
computed: {
  newStr() { // 對data的數據重新處理
    return this.str + 'hha'
  },
  list() { // 獲取Vuex中的數據(經常用到)
    return this.$store.state.btnMenu.btnPowerList
  }
},
mounted(){}
...

中規中矩沒得說,這裏computed是當作分段式的組件內部方法

重點看看Vue3中computed如何實現。

...
setup() {
  const count = ref(3)
  console.log(count.value) // => 3
  const newCount = computed(() => count.value + 1)
  console.log(newCount.value) // => 4
}
...

倘若需要在計算屬性中獲取Vuex的數據的話,那麼可以使用Vuex提供的 useStore 模塊獲取到store的實例

import { computed, defineComponent } from "vue"
import { useStore } from 'vuex'
export default defineComponent({
  setup() {
    const store = useStore()
    const list = computed(() => store.state.list)
    return {
      list
    }
  }
})

watch與watchEffect監聽?

watch監聽在Vue使用的場景也是比較多的。老規矩,先來看看Vue2是怎麼寫的,有對比才有傷害😂 😂

...
watch: {
  bankName(newValue,oldValue) {
    consoel.log(newValue,oldValue)
  }
},
methods:{}
...

來看看Vue3怎麼寫吧

<template>
  <div>count:{{count}}</div>
</template>

<script>
import { defineComponent, ref, watch } from "vue"
export default defineComponent({
  setup() {
    const count = ref(10)
    setTimeout(() => {
      count.value = 20
    }, 2000)
    watch(count, (newValue, oldValue) => {
      console.log(oldValue)
      console.log(newValue)
    })
    return {
      count
    }
  }
})
</
script>

然後watch監聽到count變化,預期地打印

當我們想定義一個響應式對象怎麼辦呢?這裏通常選用 reactive ,當然ref也可以定義一個對象。

<template>
  <div>person對象:名字:{{person.name}},年齡:{{person.age}}</div>
</template>

<script>
import { defineComponent, reactive, watch } from "vue"
export default defineComponent({
  setup() {
    const person = reactive({
      name: '前端發現',
      age: 18
    })
    setTimeout(() => {
      person.name = '我是reactive定義的name屬性更改後的數據'
    }, 2000)

    watch(() => person.name, (newValue, oldValue) => {
      console.log(oldValue)
      console.log(newValue)
    })
    return {
      person
    }
  }
})
</
script>
...

可以看到,這裏問採用了函數的形式返回了需要監聽的數據.() => person.name。來看看案例的效果:

以上都是監聽單一的數據,多個屬性怎麼監聽呢?直接上🌰

<template>
  <div>count:{{count}}</div>
  <div>person對象:名字:{{person.name}},年齡:{{person.age}}</div>
</template>

<script>
import { defineComponent, reactive, ref, watch } from "vue"
export default defineComponent({
  setup() {
    const count = ref(10)
    const person = reactive({
      name: '前端發現',
      age: 18
    })
    setTimeout(() => {
      count.value = 20
      person.name = '我是reactive定義的name屬性更改後的數據'
      person.age = 22
    }, 2000)

    watch([count, () => person.name, () => person.age], ([newCount, newName, newAge], [oldCount, oldName, oldAge
    ]) => {
      console.log(oldCount, oldName, oldAge)
      console.log(newCount, newName, newAge)
    })
    return {
      count,
      person
    }
  }
})
</
script>

直接數組的形式監聽多個數據

除了watch之外,Vue3還誕生出了 watchEffect ,看起來像是watch Plus(我暫且這樣理解吧),官方是怎麼定義這個API的呢?

在響應式地跟蹤其依賴項時立即運行一個函數,並在更改依賴項時重新運行它。

//當然這裏是需要從vue導入模塊滴
import { watchEffect } from "vue"
...
const count = ref(10)
watchEffect(() => console.log(count.value)) // => 10

setTimeout(() => {
  count.value = 20 立即執行watchEffect方法,調出打印 // => 20
}, 1000)

先看效果:

可以看到使用 watchEffect 並沒有之前 watch 的更改前數據,也不需要傳入監聽的數據源 ,而是直接執行一個函數,可以獲取到更新後的數據。

同樣的,監聽多個的話也是可以的

...
watchEffect(() => {
  console.log(count.value)
  console.log(person.name)
})
...

總結:watch 🆚  watchEffect

  • watchEffect 不需要指定監聽的屬性,他會自動的收集依賴,只要在回調函數中引用到了響應式的屬性,那麼當這些屬性變動的時候,這個回調都會執行,而 watch 只能監聽指定的屬性而作出變動(v3開始能夠同時指定多個)
  • watch 能夠獲取到新值與舊值(更新前的值),而 watchEffect 是拿不到的
  • watchEffect 在組件初始化的時候就會執行一次用以收集依賴,收集到的依賴發生變化時再執行。而 watch 則是直接指定依賴項

片段是啥?

在 Vue 3 中,組件現在正式支持多根節點組件,即片段!

<template>
  <div>我是其中一個div</div>
  <header>...</header>
  <footer>...</footer>
</template>

組件狀態驅動的 CSS 變量真香?

聽起來就感覺非常逼格,它其實就是將css用到的屬性值在組件內定義一個變量去替換。目前這個API目前還在試驗性階段!

<template>
  <div class="myClass">我是SFC style CSS variable injection</div>
</template>

<script>
import { reactive, ref, toRefs } from "vue"
export default {
  setup() {
    const minColor = ref('red')
    const styleJs = reactive({
      color: 'blue',
      fontSize: '20px',
      fontWeight: '700',
      textDecoration: 'underline'
    })
    return { /
/ 這裏不能忘記return出去
      minColor,
      ...toRefs(styleJs),
    }
  }
}
</
script>

<style lang="scss" scoped>
.myClass {
  text-decorationv-bind(textDecoration);
  font-weightv-bind(fontWeight);
  colorv-bind(minColor);
  font-sizev-bind(fontSize);
}
</style>

來看看效果:

可以看到 myClass 類名加上我們使用 v-bind 綁定的CSS屬性值

值得說明的是,在return中,我使用了 ...toRefs() API,不使用的話那麼在寫綁定styleJs對象的屬性值時就需要注意一下

.myClass {
  text-decorationv-bind('styleJs.textDecoration');
  font-weightv-bind('styleJs.fontWeight');
  colorv-bind(minColor);
  font-sizev-bind('styleJs.fontSize');
}

現在看到的樣式綁定上的屬性名上會有一點點的變化:

有興趣的朋友可以看看咱們尤大大對 組件狀態驅動的 CSS 變量 的提案

1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設計模式 重溫系列(9篇全)
4.  正則 / 框架 / 算法等 重溫系列(16篇全)
5.  Webpack4 入門(上) ||  Webpack4 入門(下)
6.  MobX 入門(上)  ||   MobX 入門(下)
7. 120 +篇原創系列彙總

回覆“加羣”與大佬們一起交流學習~

點擊“閱讀原文”查看 120+ 篇原創文章

本文分享自微信公衆號 - 前端自習課(FE-study)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章