Skip to content

vue3.5 重要更新内容

解构 defineProps

在 Vue 3.5 之前,defineProps 不能直接解构。如果需要解构,可能会丢失响应式特性。而对于 props 的默认值,则需要配合 withDefaults 使用。

示例代码

父组件代码:

vue
<script setup>
import ChildComp from './ChildComp.vue';
</script>

<template>
  <ChildComp></ChildComp>
</template>

子组件代码:

在 3.5 之前需要使用 withDefaults

vue
<script setup lang="ts">
import { defineProps, withDefaults } from 'vue'

withDefaults(defineProps<{
  type?: 'card' | 'panel'
}>(), {
  type: 'card'
})

</script>

<template>
  <div>
    <!-- 默认显示 card -->
    {{ type }}
  </div>
</template>

跳转到 Vue SFC Playground 查看效果。

在 3.5 之后,defineProps 支持直接解构,并且可以设置默认值:

vue
<script setup lang="ts">
import { defineProps } from 'vue'

const { type = 'panel' } = defineProps<{
  type?: 'card' | 'panel'
}>()

// 这样是监听不到的
watch(type, () => {})

// 这样是可以监听到的
watch(() => type, () => {})

</script>

<template>
  <div>
    <!-- 默认显示 panel -->
    {{ type }}
  </div>
</template>

跳转到 Vue SFC Palyground 查看效果。

注意

但是通过解构的方式还有个弊端,就是使用 watch 的时候,需要传递一个 getter 才能够被监听。

useId

Vue 3.5 新增了 useId 方法,用于生成全局唯一的自增 ID。每个组件实例中生成的 ID 是独立的,不会重复。

使用示例

vue
<script setup>
import { useId } from 'vue'

const id = useId()
</script>

跨多个应用的唯一性

在同一个 createApp 实例中,useId 保证生成的 ID 是唯一的。如果需要在多个 createApp 实例中确保唯一性,可以通过设置 ID 前缀实现:

ts
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.config.idPrefix = 'app1-'
app.mount('#app')

useTemplateRef

在 Vue 3.5 之前,我们通过 ref 获取 DOM 或组件引用。缺点是:变量名必须与 ref 的值保持一致,且 ref 本身也只是为了声明响应式数据设计的。

传统方式

vue
<script setup lang="ts">
import { ref } from 'vue'

const buttonRef = ref<HTMLButtonElement | null>(null)
console.log(buttonRef.value)
</script>

<template>
  <button ref="buttonRef"></button>
</template>

使用 useTemplateRef

Vue 3.5 提供了更灵活的 useTemplateRef 方法,允许自由命名引用变量:

vue
<script setup lang="ts">
import { useTemplateRef } from 'vue'

const buttonEl = useTemplateRef<HTMLButtonElement>('buttonRef')
console.log(buttonEl.value)
</script>

<template>
  <button ref="buttonRef"></button>
</template>

onWatcherCleanup

watch 函数触发时,希望做一些清楚副作用的时候很有用,比如下面这样:

方式一

vue
<script setup>
import { watch, ref, onWatcherCleanup } from 'vue'

const num = ref(0)

watch(num, newVal => {
  const handle = () => {
    console.log('click', newVal)
  }

  window.addEventListener('click', handle)
  // 在下次 watch 触发时调用
  onWatcherCleanup(() => {
    window.removeEventListener('click', handle)
  })
})
</script>

方式二

vue
<script setup>
import { watch, ref } from 'vue'

const num = ref(0)

watch(num, (newVal, oldVal, onCleanup) => {
  const handle = () => {
    console.log('click', newVal)
  }

  window.addEventListener('click', handle)
  // 在下次 watch 触发时调用
  onCleanup(() => {
    window.removeEventListener('click', handle)
  })
})
</script>

隐藏功能:watch

在 Vue 3.5 中,watch 的深度监听新增了层级限制功能。通过设置 deep 的值,可以指定监听的对象层级深度。

示例代码

vue
<script setup>
import { watch, reactive } from 'vue'

const state = reactive({
  a: {
    b: {
      c: 1
    }
  }
})

watch(
  () => state,
  () => {
    console.log('watch')
  },
  {
    deep: 2
  }
)
</script>

watch 的其他隐藏功能看这里 watch的暂停、恢复、停止