1、内容系个人翻译自 Vue 3.0 Beta 版文档中 Migration From Vue 2 章节
2、不一定准确,欢迎交流(别人都翻过几百遍了吧,再说也没人看)
3、水平有限、随时太监
全局 API <MigrationBadges :badges="$frontmatter.badges" />
Vue 2.x拥有大量的全局API与配置,这些全局API与配置可以全局影响到Vue的行为方式。 例如,你可以通过 Vue.component
API 创建一个全局Vue组件,如下:
Vue.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">点了 {{ count }} 次。</button>'
})
类似的,这是一个全局指令的定义方式:
Vue.directive('focus', {
inserted: el => el.focus()
})
诚然这种方式很方便,但它也导致了几个问题。从技术上讲,Vue 2 并没有“应用”的概念。 我们定义的应用只是简单地通过 new Vue()
所创建的一个根Vue实例。 每一个根实例都是由同一个 Vue 构造器创建的,而它们共用相同的全局配置, 导致的结果就是:
- 在测试的过程中,全局配置容易意外地污染到其他测试样例,用户需要小心地把源全局配置存储起来,并在每个测试样例结束之后将这些全局配置恢复至原样(例如:重置
Vue.config.errorHandler
)。 有些 API 像Vue.use
和Vue.mixin
并没有办法逆转他们使用效果。这就导致了涉及插件的测试会特别棘手。 实际上,vue-test-utils 需要实现一个特殊的 APIcreateLocalVue
来解决这个问题:
import { createLocalVue, mount } from '@vue/test-utils'
// 创建一个继承自 Vue 的构造器
const localVue = createLocalVue()
// 将一个插件“全局”地挂载到这个“局部”的 Vue 构造器上
localVue.use(MyPlugin)
// 再将这个 Vue 构造器传递给 mount 函数
mount(Component, { localVue })
-
这样的特性导致我们很难在一个页面内的同个 Vue 副本的不同“应用”上使用不同的全局配置
// 这将同时影响到两个根实例 Vue.mixin({ /* ... */ }) const app1 = new Vue({ el: '#app-1' }) const app2 = new Vue({ el: '#app-2' })
为了避免这些问题,在 Vue 3 中,我们引入了:
全新的全局API: createApp
调用 createApp
将返回一个 应用实例,这是一个 Vue 3 中的全新概念。
import { createApp } from 'vue'
const app = createApp({})
应用实例将暴露一个现有全局 API 的子集。大致上讲就是, 任意能全局干预到 Vue 的行为的 API 现在都被转移到了应用实例下。以下表格列举了现有的全局 API 与实例 API 的对应关系:
2.x 全局 API | 3.x 实例 API (应用(app) ) |
---|---|
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 (见下方) |
如 Global API Treeshaking 中描述的那样,其余不会影响到全局行为的 API 现已作为具名 ES 模块提供给用户导入。
config.productionTip
已移除
在Vue 3.x,提示语 “use production build” 只会在当你在使用 “dev + full build” (包含了运行时+编译器及警告的构建模式)构建应用时显示。
对于 ES 模块的构建,由于它们一般与打包工具配套使用,并且在大多数情况下 CLI 或者模版文件都会将生产环境配置好,因此该提示将不再显示。
config.ignoredElements
现改为 config.isCustomElement
引入该配置项旨在支持原生的自定义元素,所以将该选项这样重命名可以更好地表达它的作用。新的选项将接收一个更加灵活的函数以取代原先的 字符串/正则表达式 方式,如:
// 之前
Vue.config.ignoredElements = ['my-el', /^ion-/]
// 现在
const app = Vue.createApp({})
app.config.isCustomElement = tag => tag.startsWith('ion-')
::: tip 重要
在 Vue 3.0 中,检查元素是否是一个组件的过程转移到了模版编译阶段,因此该配置项只能在运行时+编译器版本中使用。当使用仅运行时版本构建应用时,isCustomElement
必须通过构建配置传递给@vue/compiler-dom
,例如: 通过 vue-loader 的 compilerOptions
选项.
- 当使用仅运行时版本构建应用时使用了
config.isCustomElement
,系统将通过一条警告信息提示用户需要构建配置传递该参数; - 这将是一项新的Vue CLI的顶层配置项。 :::
插件作者须知
常见的作者们导入加载插件的方法是,通过 Vue.use
自动加载插件的UMD版本。例如,以下展示了官方的 vue-router
插件在浏览器环境中的加载:
var inBrowser = typeof window !== 'undefined'
/* … */
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
}
而在 Vue 3 中,use
这个全局API已经不再使用,该方法已经无法正常工作并在调用 Vue.use()
的时候会触发一个警告。取而代之的是,插件的使用者需要明确地在应用实例中声明插件的使用:
const app = createApp(MyApp)
app.use(VueRouter)
挂载应用实例
当通过 createApp(/* options */)
初始化后,应用实例 app
即可通过 app.mount(domTarget)
方式挂载到一个Vue根实例:
import { createApp } from 'vue'
import MyApp from './MyApp.vue'
const app = createApp(MyApp)
app.mount('#app')
经过这些修改,本篇开头提及的 component
及 directive
方法可以重写成这样:
const app = createApp(MyApp)
app.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">点了 {{ count }} 次。</button>'
})
app.directive('focus', {
mounted: el => el.focus()
})
// 伴随着组件树的作用,现在每一个通过 app.mount() 挂载的应用实例都将获得相同的
// “button-counter” 组件与“focus”指令而无需污染全局环境。
app.mount('#app')
Provide / Inject
跟在 2.x 中在根实例上使用 provide
参数类似,Vue 3 的应用实例也可提供可注入到实例内的任意组件的依赖项:
// 入口处
app.provide({
guide: 'Vue 3 Guide'
})
// 子组件处
export default {
inject: {
book: {
from: guide
}
},
template: `<div>{{ book }}</div>`
}
应用间共享配置
以下是一种共享配置的方式,如要创建一个共享组件或指令的工厂函数:
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')
现在 focus
这个指令即可以被 Foo 和 Bar 实例以及它们的子孙实例中所使用。
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: DarkNin 原文链接:https://juejin.im/post/6859427370080665613