【Vuejs】1058- 盤點 Vue3 那些有趣的 API
從開始的Vue到Vue2再到現(xiàn)在的Vue3,前端開發(fā)人員一直被迫營業(yè),永遠也追不上尤大大寫代碼的腳步?? 。
今天我們放慢追趕的腳步,一起來看看尤大大在Vue3書寫了哪些有趣的API,有些可能說不上哪里有趣,但是看起來就是比之前舒服一些(強迫癥在線發(fā)作...)。文末有尤大大連夜寫的新需求
data選項哪去了?
回想我們在Vue2中創(chuàng)建響應(yīng)式數(shù)據(jù)是這樣的:
...
data() {
return {
num:1
}
}
...
而Vue3會 setup 組合式API這個選項了,為此引入了ref、reactive等響應(yīng)式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 //不具備響應(yīng)式
const refNum = ref(2)
const state = reactive({
name: '小黃',
age: 18
})
return {
num,
refNum,
state
}
}
})
</script>
你可以看到Vue2的data選項已經(jīng)被ref、reactive這樣的API給替換了。
那么在setup如何對ref、reactive聲明的數(shù)據(jù)修改操作呢?
...
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 聲明的數(shù)據(jù)可以直接使用 .value 這種形式更新數(shù)據(jù)。但是你也許會疑問為什么在<tempalte></template>視圖中為什么不需要 .value ,其實是vue內(nèi)部做了操作。另外,打印一下可以看到ref聲明數(shù)據(jù):

reactive 也是響應(yīng)式的聲明,它是返回對象的響應(yīng)式副本
...
setup() {
const state = reactive({
name: '小黃',
age: 18
})
console.log(state) // =>
}
...
我們直接打印下state對象,它其實是一個Proxy對象:
...
setup() {
console.log(state.name) // => 小黃
console.log(state.age) // => 18
//對數(shù)據(jù)更改
setTimeout(() => {
state.age = 20
console.log(state.age) // => 20
}, 1000)
}
...
也許你已經(jīng)注意到了開頭舉的例子——所有聲明的變量都被 return 出去了,這看起來有什么好處呢?
可以更加清晰得知道,數(shù)據(jù)與視圖之前的關(guān)系。setup里對數(shù)據(jù)操作,視圖渲染return出來的數(shù)據(jù) 更好的保護組件獨有的數(shù)據(jù),不需要暴露給視圖的數(shù)據(jù)我就不寫在return里中
再者,你可能會討厭為什么通過 reactive 聲明的數(shù)據(jù)在視圖中使用的時候又要 xx.屬性名 的方式才行,有辦法不寫嗎?有!尤大大滿足開發(fā)者的一切便捷編碼習慣。toRefs 就出來了,在結(jié)合ES9的擴展運算符 ... 就可以滿足要求了??????
<template>
//這里不再需要state包裹了,屬性已經(jīng)被展開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的數(shù)據(jù)重新處理
return this.str + 'hha'
},
list() { // 獲取Vuex中的數(shù)據(jù)(經(jīng)常用到)
return this.$store.state.btnMenu.btnPowerList
}
},
mounted(){}
...
中規(guī)中矩沒得說,這里computed是當作分段式的組件內(nèi)部方法
重點看看Vue3中computed如何實現(xiàn)。
...
setup() {
const count = ref(3)
console.log(count.value) // => 3
const newCount = computed(() => count.value + 1)
console.log(newCount.value) // => 4
}
...
倘若需要在計算屬性中獲取Vuex的數(shù)據(jù)的話,那么可以使用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監(jiān)聽?
watch監(jiān)聽在Vue使用的場景也是比較多的。老規(guī)矩,先來看看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監(jiān)聽到count變化,預(yù)期地打印

當我們想定義一個響應(yīng)式對象怎么辦呢?這里通常選用 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: '前端發(fā)現(xiàn)',
age: 18
})
setTimeout(() => {
person.name = '我是reactive定義的name屬性更改后的數(shù)據(jù)'
}, 2000)
watch(() => person.name, (newValue, oldValue) => {
console.log(oldValue)
console.log(newValue)
})
return {
person
}
}
})
</script>
...
可以看到,這里問采用了函數(shù)的形式返回了需要監(jiān)聽的數(shù)據(jù).() => person.name。來看看案例的效果:
以上都是監(jiān)聽單一的數(shù)據(jù),多個屬性怎么監(jiān)聽呢?直接上??
<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: '前端發(fā)現(xiàn)',
age: 18
})
setTimeout(() => {
count.value = 20
person.name = '我是reactive定義的name屬性更改后的數(shù)據(jù)'
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>
直接數(shù)組的形式監(jiān)聽多個數(shù)據(jù)

除了watch之外,Vue3還誕生出了 watchEffect ,看起來像是watch Plus(我暫且這樣理解吧),官方是怎么定義這個API的呢?
在響應(yīng)式地跟蹤其依賴項時立即運行一個函數(shù),并在更改依賴項時重新運行它。
//當然這里是需要從vue導入模塊滴
import { watchEffect } from "vue"
...
const count = ref(10)
watchEffect(() => console.log(count.value)) // => 10
setTimeout(() => {
count.value = 20 立即執(zhí)行watchEffect方法,調(diào)出打印 // => 20
}, 1000)
先看效果:
可以看到使用 watchEffect 并沒有之前 watch 的更改前數(shù)據(jù),也不需要傳入監(jiān)聽的數(shù)據(jù)源 ,而是直接執(zhí)行一個函數(shù),可以獲取到更新后的數(shù)據(jù)。
同樣的,監(jiān)聽多個的話也是可以的
...
watchEffect(() => {
console.log(count.value)
console.log(person.name)
})
...
總結(jié):watch ?? watchEffect
watchEffect 不需要指定監(jiān)聽的屬性,他會自動的收集依賴,只要在回調(diào)函數(shù)中引用到了響應(yīng)式的屬性,那么當這些屬性變動的時候,這個回調(diào)都會執(zhí)行,而 watch 只能監(jiān)聽指定的屬性而作出變動(v3開始能夠同時指定多個) watch 能夠獲取到新值與舊值(更新前的值),而 watchEffect 是拿不到的 watchEffect 在組件初始化的時候就會執(zhí)行一次用以收集依賴,收集到的依賴發(fā)生變化時再執(zhí)行。而 watch 則是直接指定依賴項
片段是啥?
在 Vue 3 中,組件現(xiàn)在正式支持多根節(jié)點組件,即片段!
<template>
<div>我是其中一個div</div>
<header>...</header>
<footer>...</footer>
</template>
組件狀態(tài)驅(qū)動的 CSS 變量真香?
聽起來就感覺非常逼格
,它其實就是將css用到的屬性值在組件內(nèi)定義一個變量去替換。目前這個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-decoration: v-bind(textDecoration);
font-weight: v-bind(fontWeight);
color: v-bind(minColor);
font-size: v-bind(fontSize);
}
</style>
來看看效果:

可以看到 myClass 類名加上我們使用 v-bind 綁定的CSS屬性值
值得說明的是,在return中,我使用了 ...toRefs() API,不使用的話那么在寫綁定styleJs對象的屬性值時就需要注意一下
.myClass {
text-decoration: v-bind('styleJs.textDecoration');
font-weight: v-bind('styleJs.fontWeight');
color: v-bind(minColor);
font-size: v-bind('styleJs.fontSize');
}
現(xiàn)在看到的樣式綁定上的屬性名上會有一點點的變化:

有興趣的朋友可以看看咱們尤大大對 組件狀態(tài)驅(qū)動的 CSS 變量 的提案

回復“加群”與大佬們一起交流學習~
點擊“閱讀原文”查看 120+ 篇原創(chuàng)文章
