完整版请参考: v3-migration.vuejs.org/zh/
全局API
createApp
解决了全局配置共享一个 Vue 副本
解决了污染其他测试用例
全局改变 Vue 行为的 API Vue3.x 移动到应用实例上
config.productionTip
移除
config.ignoredElements
替换为 config.isCustomElement
重点: Vue.prototype
替换为 config.globalProperties
js
// 之前 - Vue 2
Vue.prototype.$http = () => {}
// 之后 - Vue 3
const app = createApp({})
app.config.globalProperties.$http = () => {}
Vue.extend
移除
重点 使用 组合式 API 来替代继承与 mixin。
Vue.extend
vue2用于创建基于 Vue 构造函数"子类",其参数为包含组件选项的对象。Vue 3.x 中使用 createApp
挂载组件
js
// 之前 - Vue 2
// 创建构造器
const Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data() {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建一个 Profile 的实例,并将它挂载到一个元素上
new Profile().$mount('#mount-point')
// 之后 - Vue 3
const Profile = {
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data() {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
}
Vue.createApp(Profile).mount('#mount-point')
使用Vue.use()会发出警告。必须在应用实例上显式指定插件如:
js
const app = createApp(MyApp)
app.use(VueRouter)
挂载 App 实例
js
const app = createApp(MyApp)
app.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
app.directive('focus', {
mounted: (el) => el.focus()
})
// 现在,所有通过 app.mount() 挂载的应用实例及其组件树,
// 将具有相同的 "button-counter" 组件和 "focus" 指令,
// 而不会污染全局环境
app.mount('#app')
Provide / Inject
在应用之间共享配置
创建工厂函数的好处是不用给每个实例分别插入指令或配置
js
import { createApp } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const createMyApp = (options) => {
const app = createApp(options)
app.directive('focus' /* ... */)
return app
}
createMyApp(Foo).mount('#foo')
createMyApp(Bar).mount('#bar')
全局 API具名导出与Treeshaking
Vue3 nextTick
等全局API支持 tree-shaking 使用方式如
js
import { nextTick } from 'vue'
nextTick(() => {
// 一些和 DOM 有关的东西
})
受此更改影响的API:
Vue.nextTick
Vue.observable
(用Vue.reactive
替换)Vue.version
Vue.compile
(仅完整构建版本)Vue.set
(仅兼容构建版本)Vue.delete
(仅兼容构建版本)
内部帮助器
内部组件/帮助器以具名方式导出。
编译器只在代码被使用到时才引入并输出它。 只有在应用实际使用了 Transition
组件它才会被导入。
js
<transition>
<div v-show="ok">hello</div>
</transition>
//将编译为类似于以下的内容:
import { h, Transition, withDirectives, vShow } from 'vue'
export function render() {
return h(Transition, [withDirectives(h('div', 'hello'), [[vShow, this.ok]])])
}
插件中的用法
如果使用了 webpack \rollup,可能会导致 Vue 的源代码输出打包到插件中。为了防止发生这种情况配置模块打包工具以将 Vue 从最终的打包产物中排除。
js
// webpack.config.js
module.exports = {
/*...*/
externals: {
vue: 'Vue'
}
}
// rollup.config.js
export default {
/*...*/
external: ['vue']
}
如果你的插件依赖到了受影响的 Vue 2.x 全局 API,在 Vue 3 中,必须显式导入例如:
js
import { nextTick } from 'vue'
const plugin = {
install: app => {
nextTick(() => {
// ...
})
}
}
函数式组件
2.x 中函数式组件带来的性能提升在 3.x 中已经可以忽略不计
js
import { h } from 'vue'
const DynamicHeading = (props, context) => {
return h(`h${props.level}`, context.attrs, context.slots)
}
DynamicHeading.props = ['level']
export default DynamicHeading
接收两个参数:props
和 context
。context
参数是一个对象,包含组件的 attrs
、slots
和 emit
property。
在 Vue 3 中,所有的函数式组件都是用普通函数创建的。换句话说,不需要定义 { functional: true }
组件选项。
单文件组件 (SFC)
在 3.x 中,有状态组件和函数式组件之间的性能差异已经大大减少,并且在大多数用例中是微不足道的。
js
<template>
<component
v-bind:is="`h${$props.level}`"
v-bind="$attrs"
/>
</template>
<script>
export default {
props: ['level']
}
</script>