Vue3之于Vue2最大的變化,當(dāng)屬composition API了代态,而除了引入composition API外,一些我們在Vue2上經(jīng)常使用的東西到了Vue3時(shí)也發(fā)生了不小的變化疹吃,本文將介紹一些有Vue2到Vue3中幾個比較重要且常用的知識點(diǎn)蹦疑。
Options API與Composition API
Options API是把代碼分類寫在幾個Option中:
export default {
components: {
},
data() {
},
computed: {
},
watch: {
},
mounted() {
},
}
Composition API沒有固定的代碼分類,可以自由按自己的邏輯組織代碼結(jié)構(gòu)萨驶。
當(dāng)組件比較簡單只有一個邏輯的時(shí)候歉摧,option模式可以很快瀏覽組件代碼,可讀性非常高,新手友好叁温。但如果組件代碼龐大復(fù)雜豆挽,option的缺陷就很明顯,需要在各Option中橫跳才能分清功能模塊券盅。這時(shí)Composition 模式就更有優(yōu)勢帮哈,處理同一個模塊的自行組織或者提取hook,而這個需要開發(fā)者的自覺锰镀,優(yōu)點(diǎn)即缺點(diǎn)娘侍,代碼組織不規(guī)范就會造成混亂。
文中代碼示例使用setup語法糖 + ts
v-model
支持多個v-model
在Vue3
中泳炉,可以通過參數(shù)來達(dá)到一個組件支持多個v-model
的能力憾筏。
// 父組件
<template>
<child v-model="name" v-model:email="email" />
<p>姓名:{{ name }}</p>
<p>郵箱:{{ email }}</p>
</template>
<script lang="ts" setup>
import child from './child.vue'
import { ref } from 'vue'
const name = ref<string>('張三')
const email = ref<string>('666@qq.com')
</script>
// 子組件
<template>
<button @click="updateName">更新name</button>
<button @click="updateEmail">更新email</button>
</template>
<script lang="ts" setup>
import {defineEmits} form 'vue'
// 定義emit
const emits = defineEmits<{
(e: 'update:modelValue', value: string): void
(e: 'update:email', value: string): void
}>()
const updateName = () => {
emits('update:modelValue', '李四')
}
const updateEmail = () => {
emits('update:email', '123456@qq.com')
}
</script>
如果v-model
沒有使用參數(shù),則其默認(rèn)值為modelValue
花鹅,如上面的第一個v-model
氧腰,注意此時(shí)不再是像Vue2那樣使用$emit('input')
了,而是統(tǒng)一使用update:xxx
的方式刨肃。
廢棄.sync
在Vue2中古拴,由于一個組件只支持一個v-model
,當(dāng)我們還有另外的值也想要實(shí)現(xiàn)雙向綁定更新時(shí)真友,往往用.sync
修飾符來實(shí)現(xiàn)黄痪,而在Vue3中該修飾符已被廢棄,因?yàn)?code>v-model可以支持多個盔然,所以.sync
也就沒有存在的必要了桅打。
watch
不同數(shù)據(jù)類型的監(jiān)聽
基礎(chǔ)數(shù)據(jù)類型的監(jiān)聽:
const name = ref<string>('張三')
watch(name, (newValue, oldValue) => {
console.log('watch===', newValue, oldValue)
})
復(fù)雜數(shù)據(jù)類型的監(jiān)聽:
interface UserInfo {
name: string
age: number
}
const userInfo = reactive<UserInfo>({
name: '張三',
age: 10
})
// 監(jiān)聽整個對象
watch(userInfo, (newValue, oldValue) => {
console.log('watch userInfo', newValue, oldValue)
})
// 監(jiān)聽某個屬性
watch(() => userInfo.name, (newValue, oldValue) => {
console.log('watch name', newValue, oldValue)
})
支持監(jiān)聽多個源
在Vue3
里,watch
多了一個特性愈案,可以傳入一個數(shù)組同時(shí)偵聽多個數(shù)據(jù)挺尾,這比起Vue2
確實(shí)優(yōu)雅多了,以往在Vue2
中為了實(shí)現(xiàn)同時(shí)監(jiān)聽多個數(shù)據(jù)站绪,往往需要借助computed遭铺,現(xiàn)在在Vue3里我們可以少一些不必要的代碼了。
const name = ref<string>('張三')
const userInfo = reactive({
age: 18
})
// 同時(shí)監(jiān)聽name和userInfo的age屬性
watch([name, () => userInfo.age], ([newName, newAge], [oldName, oldAge]) => {
//
})
watchEffect
watchEffect與watch的區(qū)別
相比Vue2
崇众,Vue3多
了watchEffect
這個API掂僵,watchEffect
傳入一個函數(shù)參數(shù)航厚,該函數(shù)會立即執(zhí)行顷歌,同時(shí)會響應(yīng)式的最終函數(shù)內(nèi)的依賴變量,并在依賴發(fā)生改變時(shí)重新運(yùn)行改函數(shù)幔睬。
const name = ref<string>('張三')
const age = ref<number>(18)
watchEffect(() => {
console.log(`${name.value}:${age.value}`) // 張三:18
})
setTimeout(() => {
name.value = '李四' // 李四:18
}, 3000)
setTimeout(() => {
age.value = 20 // 李四:20
}, 5000)
和watch的區(qū)別:
- 運(yùn)行時(shí)機(jī)不同眯漩,
watchEffect
會立即執(zhí)行,相當(dāng)于設(shè)置了immediate: true
的watch
。 -
watchEffect
無法獲取改變前后的值赦抖。 - 與
watch
顯示的指定依賴源不同舱卡,watchEffect
會自動收集依賴源。
$attrs
Vue3中队萤,$attrs
包含父組件中除props和自定義事件外的所有屬性集合轮锥。
不同于Vue2
,$attrs
包含了父組件的事件要尔,因此$listenners
則被移除了舍杜。
// 父組件
<template>
<child id="root" class="test" name="張三" @confirm="getData" />
</template>
<script lang="ts" setup>
const getData = () => {
console.log('log')
}
</script>
// 子組件
<template>
<div>
<span>hello:{{ props.name }}</span>
</div>
</template>
<script lang="ts">
export default {
inheritAttrs: false
}
</script>
<script lang="ts" setup>
import { defineProps, useAttrs} from 'vue'
const props = defineProps(['name'])
const attrs = useAttrs()
console.log('attrs', attrs)
</script>
使用v-bind
即可實(shí)現(xiàn)組件屬性及事件透傳:
// 父組件
<template>
<child closeable @close="onClose" />
</template>
<script lang="ts" setup>
const onClose = () => {
console.log('close')
}
</script>
// 子組件
<template>
<div>
<el-tag v-bind="attrs">標(biāo)簽</el-tag>
</div>
</template>
<script lang="ts" setup>
import {useAttrs} from 'vue'
const attrs = useAttrs()
</script>
使用ref
訪問子組件
在Vue2
中,使用ref
即可訪問子組件里的任意數(shù)據(jù)及方法赵辕,但在Vue3
中則必須使用defineExpose
暴露子組件內(nèi)的方法或?qū)傩圆拍鼙桓附M件所調(diào)用既绩。
// 父組件
<template>
<child ref="childRef" />
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
const childRef = ref()
onMounted(() => {
childRef.value.getData()
})
</script>
// 子組件
<script lang="ts" setup>
import { defineExpose } from 'vue'
const getData = () => {
console.log('getData')
}
const name = ref('張三')
defineExpose({
getData,
name
})
</script>
完畢~
學(xué)習(xí)參考:
vue3文檔:https://cn.vuejs.org/guide/introduction.html
https://juejin.cn/post/7139721466722910245#heading-9