都来自于官网的的升级文档,官网文档点击我
异步组件
1, overview
2.x(before)
// simple
const asyncPage = () => import('./NextPage.vue')
//advanced
const asyncPage = {
component: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
}
3.x(after)
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// // simple ---- Async component without options
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
// //advanced ---- Async component with options
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'), // 注意这里是loader,不是component关键字
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
2 loader function change
2.x(before)
const oldAsyncComponent = (resolve, reject) => {
/* ... */
}
3.x(after)
const asyncComponent = defineAsyncComponent(
() =>
new Promise((resolve, reject) => {
/* ... */
})
)
指令的变化
指令的变化主要是API名字的变动,新的API指令名字类似于组件的生命周期
- 表示没有该API
2.x(before) | 3.x(after) |
---|---|
bind | beforeMount |
inserted | mounted |
- | beforeUpdate |
update | - |
componentUpdated | updated |
unbind | unmounted |
最终的API长这样:
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
2.x(before)
<p v-highlight="yellow">Highlight this text bright yellow</p>
Vue.directive('highlight', {
bind(el, binding, vnode) {
el.style.background = binding.value
}
})
3.x(after)
<p v-highlight="yellow">Highlight this text bright yellow</p>
const app = Vue.createApp({})
app.directive('highlight', {
beforeMount(el, binding, vnode) {
el.style.background = binding.value
}
})
EVENT变化
在3.x版本中:移除了 $on
, $off
, $once
这3个方法。保留了$emit
,保留这个方法是为了触发父组件里面的event handler。
所以2.x中的非父子组件的数据交换以及事件触发,就不能通过$on
or$off
来实现了。实际上我们可以自己实现一个EventHub 【通过发布订阅模式】
不过已经有第三方库实现了mitt 和 tiny-emitter
Filter
3.x 不再支持filter,可以用method
或者 computed
来代替。
Fragments
2.x 模板不支持多root节点,3.x支持多root节点
2.x(before)
<!-- Layout.vue -->
<template>
<div> <!--有且只有一个root节点-->
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>
3.x(after)
<!-- Layout.vue -->
<template>
<!--template里面可以有多个root节点-->
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
Global API tree-shaking
前景: 2.x里面我们操作dom的时候,是这样操作的。
import Vue from 'vue'
Vue.nextTick(()=>{
//Something Dom-related
})
由于2.x代码中nextTick的实现方式的原因,造成了诸如webpack等打包工具打包的时候,tree-shaking
是不能移除这一块无用的代码的,比如我们是这样写的Vue.nextTick()
,最后仍然会在build文件里面。
3.x 部分全局API被重写,已经能够支持tree-shaking。而且这些全局API只能通过ES module的具名引用形式获取到。 像这样:
import { nextTick } from 'vue'
nextTick(() => {
// something DOM-related
})
2.x中被影响的全局API
- Vue.nextTick
- Vue.observable (replaced by Vue.reactive)
- Vue.version
- Vue.compile (only in full builds)
- Vue.set (only in compat builds)
- Vue.delete (only in compat builds)
除了一些全局的Global API,一些内部组件/帮助方法也能够以具名形式导出。 好处就是,只有被使用了,最后编译的时候才能够打包输出。有使用到才被打包。
v-model 的改变 [非常重要,在自定义组件的时候的逻辑修改]
1,自定义组件的时候,v-model的属性和时间的名字修改。
prop: value
-> modelValue
event: input
-> update:modelValue
2,v-binding
的.sync
修饰器和组件的model
选项被移除,现在作为v-model的参数。
3,可以给一个组件绑定多个v-model
4,除了默认的v-model
,可以添加用户自定v-model
修饰器
2.x(before)
在2.x下,v-model
是一个语法糖,等同于value
属性和一个input
事件。
<ChildComponent v-model="pageTitle" />
<!-- 等同于 -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
如果我们想改变属性和事件的名字,不使用默认的 value
和 input
,那我们需要在ChildComponent
里面添加model
选项。
<!-- ParentComponent.vue -->
<ChildComponent v-model="pageTitle" />
// ChildComponent.vue
export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// 让value属性发挥其他作用
// this allows using the `value` prop for a different purpose
value: String,
// 用属性名title代替名字value
// use `title` as the prop which take the place of `value`
title: {
type: String,
default: 'Default title'
}
}
}
这样我们不仅能用v-model
的形式,也能用语法糖来表示,但是可以用我们的命名来。
<ChildComponent v-model="pageTitle" />
<!-- 等同于 -->
<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
关于.sync
,在2.x中,有一定的情况下,需要属性值也双向绑定,子组件可以修改父组件传递下来的属性值。
父组件引用子组件的代码:
<ChildComponent :title.sync="pageTitle" />
<!--等同于-->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
子组件修改属性值的代码:
this.$emit('update:title', newValue)
3.x(after)
在3.x下,在自定义组件上的v-model
等同于 modalValue
属性和update:modalValue
事件
prop:value
-> modelValue
event: input
-> update:modelValue
<ChildComponent v-model="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
v-model
参数(.sync的改进)
现在移除了组件里面的model
option, 代替它的是在v-model
上传递一个参数
<ChildComponent v-model:title="pageTitle" />
<!-- 等同于: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
也就是说以前.sync的方式这样修改:
<!--2.x-->
<ChildComponent :title.sync="pageTitle" />
<!--3.x-->
<ChildComponent v-model:title="pageTitle" />
v-model可以自定义修饰器
2.x只有一些默认的修饰器,比如.trim
, 3.x支持自定义修饰器了