跳至主要內容

解决问题

俞文健大约 2 分钟

Vue2.7 存在的问题

TS 支持不友好

2.7 加入了组合式 API 的写法,同时也支持 TS,但是 2.7 对 TS 的支持并不友好,2.7 不能定义插槽参数的类型,这导致如果直接解构 slotProps 的话,row 的类型为 any,读取 row 中的属性会导致编辑器报错。

下列代码在 webstorm 中会出现 “未解析的变量 itemTitle” 的报错,虽然运行没有问题,但是很影响开发体验。

<template #default="{ row }">
  {{ row.itemTitle }}
</template>

访问路由不方便

此外,由于在 2.7 中使用组合式写法,但是 vue-router 又没有提供 useRouteruseRoute 这两个 API。

useRouter 我们可以像 Vue2 一样导入 router 对象来使用,但是 useRoute 没有很好的替代品。既失去了 $route 的写法,又不能使用 useRoute,那我们如何获取路由信息呢?

我们可以使用 getCurrentInstance() 解构出一个 proxy 对象,通过 proxy.$route 可以访问路由信息。

警告

如果想要观察 route 的变化,必须监听 proxy.$route

import { watch, getCurrentInstance } from "vue"

const { proxy }: any = getCurrentInstance()
// 这种方式获取的 route 是一个固定值,它将不会变化
const route = getCurrentInstance()?.proxy.$route!

watch(() => proxy.$route, route => {
  // 可以监听 route 的变化
})

watch(() => route, route => {
  // !!不能监听 route 的变化
})

立即监听导致的引用问题

在 watch 中使用了后面定义的响应式数据,并开启立即监听,出现 Cannot access 'searchForm' before initialization 的报错。

const status = ref("1")

watch(status, status => {
  search(status)
}, {
  immediate: true
})

const searchForm = reactive({ /* some params */ })

async function search(status: string) {
  await apiSearch({
    ...searchForm, // Cannot access 'searchForm' before initialization
    status
  })
}

如果是一个普通数据,就不会出现报错。

const status = ref("1")

watch(status, () => {
  console.log(searchForm)
}, {
  immediate: true
})

const searchForm = {
  /* some params */
}

结论:开启立即监听时,不能在 watch 中引用定义在其之后的响应式数据,但是可以引用普通数据。