vue3新特性简介

本文主要介绍vue3新特性

首先,先来看一些小的变化

生命周期更名:
destroyed -> unmounted
beforeDestroy -> beforeUnmount

data选项始终声明为函数

删除 $on, $off 和 $once API

删除 Filters API,改用method 和 computed 替换

v-on不再支持使用数字(即keyCodes)作为修饰符,config.keyCodes不再受支持

在v-enter过渡类已重命名为v-enter-from和v-leave过渡类已更名为v-leave-from

接下来看一些API的更改:

1.Scaffold

vite:

1
2

npm init vite-app hello-vue3

vue-cli:

1
2
3

npm install -g @vue/cli
vue create hello-vue3

注:尤大写的vite捆绑了rollup进行打包,而且具有以下特性:

  1. 快速启动冷服务器
  2. 即时热模块更换(HMR)
  3. 真正的按需编译
  4. 更详细的日志信息

2.v-for Array Refs

v-for循环绑定的ref可以更加灵活,且定义非常方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

<template>
<div v-for="item in list" :ref="setItemRef"></div>
</template>

export default {
data() {
return {
list: []
itemRefs: []
}
},
methods: {
setItemRef(el) {
this.itemRefs.push(el)
}
},
beforeUpdate() {
this.itemRefs = []
},
updated() {
console.log(this.itemRefs)
}
}

3.defineAsyncComponent

定义异步组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14

import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'

const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))

const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})

4.Custom Directives

v-for循环绑定的ref可以更加灵活,切定义非常方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

bind - 一旦该指令被绑定到元素时执行。仅执行一次。
inserted - 在将元素插入父DOM中时执行。
update - 元素更新时调用此挂钩,但是子组件尚未更新。
componentUpdated - 组件和子组件更新后,将调用此挂钩。
unbind - 删除指令后将调用此钩子。也仅调用一次。


bind 更名为 beforeMount
inserted 更名为 mounted
beforeUpdate: 这在元素本身更新之前被调用,就像组件生命周期挂钩一样。
update 已删除
componentUpdated 更名为 updated
beforeUnmount 与组件生命周期挂钩类似,这将在卸载元素之前立即调用。
unbind 更名为 unmounted

5.Data Option

合并data来自mixin或扩展的多个返回值时,合并现在较浅而不是较深(仅合并了根级属性)。

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

const Mixin = {
data() {
return {
user: {
name: 'Jack',
id: 1
}
}
}
}

const CompA = {
mixins: [Mixin],
data() {
return {
user: {
id: 2
}
}
},
mounted(){
console.log(this.$data) // {user: { id: 2 }}
}
}

6.Fragments

组件现在可以具有多个根节点!但是,这确实需要开发人员明确定义属性应在何处分发。

1
2
3
4
5
6

<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>

7.Global API

新增 createApp 返回一个应用程序实例,现在可以将全局更改Vue行为的所有API移至应用程序实例。

1
2
3
4

import { createApp } from 'vue'

const app = createApp({})
2.x Global API 3.x Instance API
Vue.config app.config
Vue.config.productionTip 已移除
Vue.config.ignoredElements app.config.isCustomElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use

8.key attribute

key应该将放在

1
2
3
4
5

<template v-for="item in list" :key="item.id">
<div>...</div>
<span>...</span>
</template>

9.v-model

在自定义组件上使用时,v-modelprop和event的默认名称已更改:

  1. prop value-> modelValue
  2. vent input-> update:modelValue
    v-model现在可以在同一组件上进行多个绑定;
    v-bind的.sync修饰符和组件model选项已删除,并替换为v-model的一个参数;
    添加了创建自定义v-model修饰符的功能;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

// ParentComponent
<template>
<ChildComponent v-model="pageTitle" />
</template>

// ChildComponent
export default {
props: {
modelValue: String
},
methods: {
changePageTitle(title) {
this.$emit('update:modelValue', title)
}
}
}

最后,我们再来看一些重大的变化

1.reactive

Vue3 响应式实现原理是通过 ES6 的 Proxy实现的,但是对于 IE 浏览器,Vue3 也使用了 Object.defineProperty。
vue3 将Vue.observable()重命名为reactive,并提供了单独的分离。

1
2
3
4
5
6

import { reactive } from 'vue'

const state = reactive({
count: 0
})

3.ref

对于一个独立的原始值,Vue3 也提供了对应的响应式API。

1
2
3
4
5
6
7
8

import { ref } from 'vue'

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

4.toRefs

ES6 解构会破坏响应式,对于这种情况可以使用 toRefs 去避免。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

import { reactive, toRefs } from 'vue'

const book = reactive({
author: 'Vue Team',
year: '2020',
title: 'Vue 3 Guide',
description: 'You are reading this book right now ;)',
price: 'free'
})

let { author, title } = toRefs(book)

title.value = 'Vue 3 Detailed Guide'
console.log(book.title) // 'Vue 3 Detailed Guide'

5.readonly

有时我们想避免响应式更改,可以使用readonly。

1
2
3
4
5
6
7
8
9
10

import { reactive, readonly } from 'vue'

const original = reactive({ count: 0 })

const copy = readonly(original)

original.count++

copy.count++ // warning: "Set operation on key 'count' failed: target is readonly."

6.computed

有时我们需要依赖于其他状态的状态,可以通过计算属性来处理的。

1
2
3
4
5
6
7
8
9
10
11

const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})

plusOne.value = 1
console.log(count.value) // 0

7.watchEffect

为了监听响应式更改,可以使用该watchEffect方法,它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。它会返回一个停止函数,通过显式调用可以停止侦听。

1
2
3
4
5
6
7
8
9
10
11
12
13

const count = ref(0)

const stop = watchEffect(() => console.log(count.value))
// -> logs 0

setTimeout(() => {
count.value++
// -> logs 1
}, 100)

// later
stop()

8.setup

setup 将可重复部分及其功能提取到可重用的代码段中。
setup 选项接受 props 和 context 的函数,返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<template>
<div>{{ readersNumber }} {{ book.title }}</div>
</template>

<script>
import { ref, reactive } from 'vue'

export default {
setup(props, context) {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })

// expose to template
return {
readersNumber,
book
}
}
}
</script>

9.Provide / Inject

在 setup() 中使用 provide 时,我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 时来定义每个 property。
provide 函数允许你通过两个参数定义 property:
property 的 name ( 类型)
property 的 value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>

<script>
import { provide } from 'vue'
import MyMarker from './MyMarker.vue

export default {
components: {
MyMarker
},
setup() {
provide('location', 'North Pole')
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
}
</script>

在 setup() 中使用 inject 时,还需要从 vue 显式导入它。一旦我们这样做了,我们就可以调用它来定义如何将它暴露给我们的组件。
inject 函数有两个参数:
要注入的 property 的名称
一个默认的值 (可选)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'

export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')

return {
userLocation,
userGeolocation
}
}
}
</script>
扫一扫,请老师喝水