從開始的Vue到Vue2再到現在的Vue3,前端開發人員一直被迫營業,永遠也追不上尤大大寫代碼的腳步👣 。
今天我們放慢追趕的腳步,一起來看看尤大大在Vue3書寫了哪些有趣的API,有些可能說不上哪裏有趣,但是看起來就是比之前舒服一些(強迫症在線發作...)。文末有尤大大連夜寫的新需求
data選項哪去了?
回想我們在Vue2中創建響應式數據是這樣的:
...
data() {
return {
num:1
}
}
...
而Vue3會 setup 組合式API這個選項了,爲此引入了ref、reactive等響應式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: '小黃',
age: 18
})
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-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');
}
現在看到的樣式綁定上的屬性名上會有一點點的變化:
有興趣的朋友可以看看咱們尤大大對 組件狀態驅動的 CSS 變量 的提案
回覆“加羣”與大佬們一起交流學習~
點擊“閱讀原文”查看 120+ 篇原創文章
本文分享自微信公衆號 - 前端自習課(FE-study)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。