Vue3的新特性以及对TypeScript的全支持

以前使用Vue2的时候相信很多朋友都没有特别好的体验。
但是尤大发布Vue3之后,据说能够友好地拥抱TypeScript了。
今天一边谈谈Vue3大新特性一边总结一下在Vue3里使用TypeScript的方法。

新特性

Composition API

这是Vue3追加的最受注目的功能。Props和Content就可以生成全体Component都能使用和参照的参数。有点像React Hooks里记述的可以动态参照的参数。

原本的Vue2的Component里的话一般都像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: {
type: String,
required: true
}
},
data () {
return {
repositories: [],
filters: { ... },
searchQuery: ''
}
},
computed: {
filteredRepositories () { ... },
repositoriesMatchingSearchQuery () { ... },
},
watch: {
user: 'getUserRepositories'
},
methods: {
getUserRepositories () {
// using `this.user` to fetch user repositories
},
updateFilters () { ... },
},
mounted () {
this.getUserRepositories()
}
}

这样会导致Component变得沉重,本来只是想进行一个处理, 但是却分散在不同的地方,影响可读性。
像下面这样同样的处理全部总结写在一处比较好。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs, computed } from 'vue'

export default {
props: {
user: {
type: String,
required: true
}
},
setup (props) {
// using `toRefs` to create a Reactive Reference to the `user` property of props
const { user } = toRefs(props)

const repositories = ref([])
const getUserRepositories = async () => {
// update `props.user` to `user.value` to access the Reference value
repositories.value = await fetchUserRepositories(user.value)
}

onMounted(getUserRepositories)

// set a watcher on the Reactive Reference to user prop
watch(user, getUserRepositories)

const searchQuery = ref('')
const repositoriesMatchingSearchQuery = computed(() => {
return repositories.value.filter(
repository => repository.name.includes(searchQuery.value)
)
})

return {
repositories,
getUserRepositories,
searchQuery,
repositoriesMatchingSearchQuery
}
}
}
  • setup返回的值可以供全体Component使用。
  • toRefsref能够参照动态值,Component里使用hoge.value可以动态参照修改后的值。
  • 支持生命周期,onMounted里可以指定在mount之后实行的参数。
  • 使用computed后也可以生成computed value。

Teleport

Vue Component里的dom的一部分, 在渲染的时候可以在指定的dom下进行描画。
在body下描画全画面的model的时候可以使用。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>

<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})

Fragments

在route里放置多个dom.

例: (v2)

1
2
3
4
5
6
7
<template>
<div>
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>

例: (v3)

1
2
3
4
5
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>

Emits Component Option

新追加的option.
为了记录Component是怎样运行的, 推荐写在所有emit了的自定义方法里面.

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
app.component('custom-form', {
emits: {
// No validation
click: null,

// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm() {
this.$emit('submit', { email, password })
}
}
})
  • 也可以使用emit: ["click", "submit"]这样的数列来进行定义.
  • 如果使用object来指定参数的话, 将会被作为Validator来运行.

Custom Render(createRender)

可以自定义你的渲染器。
可以使用option来在渲染的时候插入特定的处理.

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { createRenderer } from '@vue/runtime-core'
import { nodeOps } from '@vue/runtime-dom'

const { render, createApp } = createRenderer({
...nodeOps,
insert: () => {},
})

// `render` is the low-level API
// `createApp` returns an app instance with configurable context shared
// by the entire app tree.
export { render, createApp }

export * from '@vue/runtime-core'

TypeScript应对

下面是重头戏TS的应对.

定义Component的时候请注意
1.script标签里进行ts的声明

1
2
3
<script lang="ts">
...
</script>

2.使用defineComponent参数
为了在Component里使用正确的类型定义,这里不使用常用的class,使用以下的参数就必须新生成一个Component.

1
2
3
4
5
import { defineComponent } from 'vue'

const Component = defineComponent({
// type inference enabled
})

改变的点:
Vue3开始对TS进行全力的支持这一点相信大家都有听过,Vue3里对TS部分进行了全部的重新定义,只是Composition API里对逻辑进行了总结, TS因此变得更好用了?