vue3.0 全局 API 的变化

发布于: 2020 年 07 月 08 日

重新设计应用程序引导程序和全局API

现在,将全局改变Vue行为的全局API移至由新的createApp方法创建的应用程序实例,并且它们的影响现在仅限于该应用程序实例。

不会改变Vue行为的全局API(例如nextTick和Advanced Reactivity API中提议的API)现在被称为Global API Treeshaking RFC中指定的导出

before

import Vue from 'vue'
import App from './App.vue'
Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)
Vue.prototype.customProperty = () => {}
new Vue({
render: h => h(App)
}).$mount('#app')
now
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.isCustomElement = tag => tag.startsWith('app-')
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)
app.config.globalProperties.customProperty = () => {}
app.mount(App, '#app')

动机

Vue当前的某些全局API和配置会永久更改全局状态。这导致一些问题

全局配置使得在测试过程中很容易意外地污染其他测试用例。用户需要小心地存储原始的全局配置,并在每次测试之后恢复它(例如,重新设置Vue.config.errorHandler)。一些api(例如Vue)。使用,Vue.mixin)甚至没有办法恢复它们的效果。这使得涉及插件的测试特别棘手

vue-test-utils必须实现特殊的API createLocalVue来处理此问题

这也使得很难在同一页面上的多个“应用”之间共享相同的Vue副本,但是具有不同的全局配置:

// this affects both root instances
Vue.mixin({ /* ... */ })
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })

详细设计

从技术上讲,Vue 2没有“应用”的概念。我们定义为应用程序的只是通过新Vue()创建的根Vue实例。从同一Vue构造函数创建的每个根实例都共享相同的全局配置。

在此提案中,我们引入了一个新的全局API createApp:

import { createApp } from 'vue'
const app = createApp({
/* root component definition */
})

调用createApp返回一个应用程序实例。应用程序实例提供了应用程序上下文。应用程序实例挂载的整个组件树共享相同的应用程序上下文,该上下文提供了先前在Vue 2.x中“全局”的配置。

全局API映射

应用程序实例公开了当前全局API的子集。经验法则是,现在可以将全局更改Vue行为的所有API移至应用程序实例。这些包括:

正如全局API树摇动中所建议的那样,所有其他不全局改变行为的全局API现在都被称为导出

唯一的例外是Vue.extend。由于全局Vue不再是新的构造函数,因此Vue.extend在构造函数扩展方面不再有意义。

对于扩展基本组件,应该使用extends选项。

对于TypeScript类型推断,请使用新的defineComponent全局API:

import { defineComponent} from 'vue'
const App = defineComponent({
/* Type inference provided */
})

注意,实现明智的defineComponent什么也不做——它只是返回传递给它的对象。但是,就类型而言,返回的值有一个合成类型的构造函数,用于手动呈现函数、TSX和IDE工具支持。这种不匹配是一种有意的权衡。

挂载应用程序实例

应用程序实例可以使用mount方法安装根组件。它的工作方式与2.x vm。$ mount()方法相似,并返回已安装的根组件实例:

const rootInstance = app.mount(App, '#app')

mount方法还可以接受通过第三个参数传递给根组件的props:

app.mount(App, '#app', {  // props to be passed to root component})

与2.x的安装行为差异

当使用包含编译器的版本并安装没有自身模板的根组件时,Vue将尝试使用安装目标元素的内容作为模板。注意3.x行为和2.x之间的区别:

在2.x中,根实例使用目标元素的externalHTML作为模板,并替换目标元素本身。

在3.x中,根实例使用目标元素的innerHTML作为模板,并且仅替换目标元素的子代。

在大多数情况下,这对应用程序的行为没有影响,唯一的副作用是,如果目标元素包含多个子元素,根实例将作为一个片段挂载。$el将指向片段的起始锚节点(一个DOM注释节点)

在Vue 3中,由于片段的可用性,建议使用模板引用直接访问DOM节点,而不是依赖于此。

Provide / Inject

应用程序实例还可以提供可以由应用程序内部的任何组件注入的依赖项:

// in the entry
app.provide({
[ThemeSymbol]: theme
})
// in a child component
export default {
inject: {
theme: {
from: ThemeSymbol
}
},
template: `<div :style="{ color: theme.textColor }" />`
}

删除config.productionTip

在3.0中,“使用产品构建”提示只会在使用“dev +完整构建”(包含运行时编译器并有警告的构建)时出现。

对于ES模块构建,由于它们与捆绑程序一起使用,并且在大多数情况下,CLI或样板文件将正确配置生产环境,因此这个技巧将不再出现。

config.ignoredElements -> config.isCustomElement 引入此配置选项旨在支持本机自定义元素,因此重命名可以更好地传达其功能。新选项还期望有一个比旧字符串/ RegExp版本具有更大灵活性的函数:

// before
Vue.config.ignoredElements = ['my-el', /^ion-/]
// after
const app = Vue.createApp({ /* ... */ })
app.config.isCustomElement = tag => tag.startsWith('ion-')

mportant:在3.0中,检查元素是否为组件的操作被移到了模板编译阶段,因此只有在使用运行时编译器时才会考虑这个配置选项。如果您使用的是运行时构建,则必须在构建设置中将isCustomElement传递到@vue/compiler-dom—例如,通过vue-loader中的compilerOptions选项。

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)
Vue.prototype.customProperty = () => {}
new Vue({
render: h => h(App)
}).$mount('#app')

发布于: 2020 年 07 月 08 日 阅读数: 5
用户头像

志学Python

关注

Ken 2019.06.12 加入

不断的探索尝试,不断探索尝试,不断探索尝试,永远不要放弃学习,前进,追求卓越,幸福就会追着你跑了,去发现自己的闪光点,在追求幸福的道路上,难免坎坷,但是思维决定幸福层度 在这里不仅仅只有技术

评论

发布
暂无评论
vue3.0 全局API的变化