Vue2 到 Vue3,重學這 5 個常用的 API

距離 Vue3 發佈已經過去一年多時間了,從 Vue2 到 Vue3 是一個不小的升級,包括周邊生態等。

雖然目前大多數開發者們在使用的仍舊以Vue2爲準,但 Vue3 顯然是 Vue 開發者們未來必須面對的,而且前不久 Vue 官方也發佈了 Vue2.7.0,使得 Vue2 可以兼容 Vue3 的 API,這讓開發者可以在項目不升級 Vue3 的情況下依舊可以使用 Vue3 的開發方式,這爲 Vue2 開發者學習 Vue3 提供了一個非常好的過渡途徑。

Vue3 之於 Vue2 最大的變化,當屬composition API了,而除了引入composition API外,一些我們在 Vue2 上經常使用的東西到了 Vue3 時也發生了不小的變化,本文將介紹一些有 Vue2 到 Vue3 中幾個比較重要且常用的知識點,歡迎感興趣的同學閱讀。

文中代碼示例使用setup語法糖 + ts

v-model

支持多個 v-model

Vue3中,可以通過參數來達到一個組件支持多個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>
// 定義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沒有使用參數,則其默認值爲modelValue,如上面的第一個v-model,注意此時不再是像 Vue2 那樣使用$emit('input')了,而是統一使用update:xxx的方式。

廢棄.sync

在 Vue2 中,由於一個組件只支持一個v-model,當我們還有另外的值也想要實現雙向綁定更新時,往往用.sync修飾符來實現,而在 Vue3 中該修飾符已被廢棄,因爲v-model可以支持多個,所以.sync也就沒有存在的必要了。

watch

不同數據類型的監聽

基礎數據類型的監聽:

const name = ref<string>('張三')
watch(name, (newValue, oldValue) ={
  console.log('watch===', newValue, oldValue)
})

複雜數據類型的監聽:

interface UserInfo {
  name: string
  age: number
}

const userInfo = reactive<UserInfo>({
  name: '張三',
  age: 10
})
// 監聽整個對象
watch(userInfo, (newValue, oldValue) ={
  console.log('watch userInfo', newValue, oldValue)
})

// 監聽某個屬性
watch(() => userInfo.name,  (newValue, oldValue) ={
  console.log('watch name', newValue, oldValue)
})

支持監聽多個源

Vue3裏,watch多了一個特性,可以傳入一個數組同時偵聽多個數據,這比起Vue2確實優雅多了,以往在Vue2中爲了實現同時監聽多個數據,往往需要藉助 computed,現在在 Vue3 裏我們可以少一些不必要的代碼了。

const name = ref<string>('張三')
const userInfo = reactive({
  age: 18
})

// 同時監聽name和userInfo的age屬性
watch([name, () => userInfo.age]([newName, newAge][oldName, oldAge]) ={
  // 
})

watchEffect

watchEffect 與 watch 的區別

相比Vue2Vue3多watchEffect這個 API,watchEffect傳入一個函數參數,該函數會立即執行,同時會響應式的最終函數內的依賴變量,並在依賴發生改變時重新運行改函數。

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 的區別:

watchEffect還是watch

建議在大部分時間裏使用watch,避免一些不必要的重複觸發。

$attrs

Vue3 中,$attrs包含父組件中除 props 和自定義事件外的所有屬性集合。

不同於Vue2$attrs包含了父組件的事件,因此$listenners則被移除了。

// 父組件
<template>
  <child id="root" class="test"  @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>
const props = defineProps(['name'])

const attrs = useAttrs()
console.log('attrs', attrs)
</script>

使用v-bind即可實現組件屬性及事件透傳:

// 父組件
<template>
  <child closeable @close="onClose" />
</template>

<script lang="ts" setup>
const onClose = () ={
  console.log('close')
}
</script>

// 子組件
<template>
  <div>
    <el-tag v-bind="attrs">標籤</el-tag>
  </div>
</template>

使用ref訪問子組件

Vue2中,使用ref即可訪問子組件裏的任意數據及方法,但在Vue3中則必須使用defineExpose暴露子組件內的方法或屬性才能被父組件所調用。

// 父組件
<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>
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/OEWXNRpSGCtLF8BPn3XOCA