Vue3 相对于 Vue2 值得关注的新特性
- Composition API 组合式 API
- 重新实现了数据响应式原理(利用 ES6 的 proxy 代替了 ES5的 Object.defineProperty)
- 源码使用 typescript 进行了重写,拥有更好的类型推导
- Virtual DOM Rewrite 重写虚拟DOM(渲染机制和优化)
- Fragment 片段
- Teleport 瞬移术
- emits 触发组件选项
Composition API 组合式 API
通过代码来理解 Composition API 的作用和好处,以下是一个实例,实现了一个能实时显示鼠标坐标位置的例子。
<template>
<h1>Hello World</h1>
<div>
x: {{ position.x }}
</div>
<div>
y: {{ position.y }}
</div>
</template>
import { onMounted, onUnmounted, reactive } from 'vue'
export default {
name: 'App',
setup() {
const position = reactive({
x: 0,
y: 0
})
const update = e => {
position.x = e.pageX
position.y = e.pageY
}
onMounted(()=>{
window.addEventListener('mousemove', update)
})
onUnmounted(()=>{
window.removeEventListener('mousemove', update)
})
return {
position
}
}
}
重构逻辑部分代码
import { onMounted, onUnmounted, reactive } from 'vue'
function useMousePosition () {
const position = reactive({
x: 0,
y: 0
})
// 定义事件处理函数
const update = e => {
position.x = e.pageX
position.y = e.pageY
}
// 注册事件
onMounted(()=>{
window.addEventListener('mousemove', update)
})
// 注销事件
onUnmounted(()=>{
window.removeEventListener('mousemove', update)
})
return position
}
export default {
name: 'App',
setup() {
const position = useMousePosition()
return {
position
}
}
}
从上述的代码中可以看出,与 position 相关的变量、函数、生命周期、逻辑操作都被集中抽离到一个 useMousePosition 这个函数中,逻辑更加耦合,整套流程代码查询的时候也比较好定位,整个处理逻辑比较清晰,易于修改。
setup 组件选项
为了开始使用组合式 API,我们首先需要一个可以实际使用它的地方。在 Vue 组件中,我们将此位置称为 setup
,setup 选项应该是一个接受 props 和 context 的函数。
props 是 setup 函数接收的第一个参数,即组件的 props 属性。context(上下文) 是 setup 函数接收的第二个参数,context 可以被解构为 { attrs, slots, emit } 这三个参数。
新的 setup 组件选项在创建组件之前执行,一旦 props 被解析,并充当合成 API 的入口点。
WARNING:setup的执行时机在:beforeCreate 之后 created之前。由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。
reactive 和 ref
reactive 函数将传递的 json 对象或者数组包装成了 proxy 对象,使其具备响应式
ref 函数可以处理基本数据类型的变量,包装原始的基本值为一个对象,使其变成响应式数据,通过 primaryValue.value 来访问或更高该响应式变量的值。
computed 和 watched 函数
computed 和 watched 可以单独作为一个函数来使用
import { computed, ref } from '@vue/composition-api'
export default {
setup() {
const refCount = ref(1)
// 只读
let computedCount = computed(() => refCount.value + 1)
console.log(computedCount)
return {
refCount,
computedCount
}
}
};
import { watch, ref } from '@vue/composition-api'
export default {
setup() {
const refCount = ref(100)
// 定义 watch,只要 count 值变化,就会触发 watch 回调
// 组件在第一次创建的时候执行一次 watch
watch(() => console.log(refCount.value), { lazy: false})
setInterval(() => {
refCount.value += 2
}, 5000)
return {
refCount
}
}
};
生命周期钩子注册内部 setup
为了使组合式 API 的特性与选项式 API 相比更加完整,我们还需要一种在 setup 中注册生命周期钩子的方法。这要归功于从 Vue 导出的几个新函数。组合式 API 上的生命周期钩子与选项式 API 的名称相同,但前缀为 on:即 mounted 看起来像 onMounted。
这些函数接受在组件调用钩子时将执行的回调。
例如代码中的 onMounted() 和 onUnmouted() 钩子函数,将在组件 mounted(加载) 和 unmouted(卸载) 的时候执行事件回调。
Virtual DOM Rewrite 重写虚拟DOM(渲染机制和优化)
利用 patch flag 优化静态树
https://www.pianshen.com/article/16291732261/
Fragment 片段
在 Vue 3 中,组件现在正式支持多根节点组件,即片段!
在 2.x 中,不支持多根组件,当用户意外创建多根组件时会发出警告,因此,为了修复此错误,许多组件被包装在一个 <div> 中。
在 3.x 中,组件现在可以有多个根节点!但是,这确实要求开发者明确定义属性应该分布在哪里。
与单个根节点组件不同,具有多个根节点的组件不具有自动 attribute 回退行为。如果未显式绑定 $attrs,将发出运行时警告。
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
// 警告
app.component('custom-layout', {
template: `
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
`
})
// 没有警告,$attrs被传递到two元素
app.component('custom-layout', {
template: `
<div class="one">one</div>
<div class="two" v-bind="$attrs">two</div>
<div class="three">three</div>
`
})
Teleport 瞬移术
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。
以模态框举例,可以在一个深度嵌套的 UI 组件中定义一个模态框,通过 Teleport To 把该模态框 append 到 body 的标签下。
Vue3 相对于 Vue2 的一些小改变
生命周期函数重命名
destroyed 生命周期选项被重命名为 unmounted
beforeDestroy 生命周期选项被重命名为 beforeUnmount
data 选项
在 3.x,data 选项已标准化为只接受返回 object 的 function。而不能像 2.x 中的那样 data 可以是一个 object
<script>
import { createApp } from 'vue'
createApp({
data() {
return {
apiKey: 'a1b2c3'
}
}
}).mount('#app')
</script>
mixins 行为改变
此外,当来自组件的 data() 及其 mixin 或 extends 基类被合并时,现在将浅层次执行合并。而不是深度合并。
const Mixin = {
data() {
return {
user: {
name: 'Jack',
id: 1
}
}
}
}
const CompA = {
mixins: [Mixin],
data() {
return {
user: {
id: 2
}
}
}
}
在 Vue 2.x中,生成的 $data 是:
{
user: {
id: 2,
name: 'Jack'
}
}
在 3.0 中,其结果将会是:
{
user: {
id: 2
}
}
Vue3 相对于 Vue2 不兼容的变化
过滤器 filters
从 Vue 3.0 开始,过滤器已删除,不再支持。