在这篇文章中,咱们将首先看看 Vue 2 应用程序中的应用程序初始化代码是如何工作的。而后咱们会看到它有哪些毛病,以及如何通过 Vue 框架第 3 版中应用的新初始化语法打消这些毛病。
咱们先说说目前 Vue 2 中的初始化形式。通常,在 src/main.js
文件中,咱们是通过调用一个新的 Vue 作为创立利用实例的构造函数来疏导利用的。
import Vue from "vue";
import App from "./App.vue";
import router from './router'
import SomeComponent from '@/components/SomeComponent.vue'
import SomePlugin from '@/plugins/SomePlugin'
const vue2AppCopy = new Vue({
router,
render: h => h(App)
});
vue2AppCopy.component('SomeComponent',SomeComponent);
vue2AppCopy.use(SomePlugin);
vue2AppCopy.$mount('#app')
这个利用实例将在咱们 SPA 的整个生命周期内为所有的逻辑服务。这所有都很好,大概 3 年来,咱们始终应用这种语法来疏导咱们的 Vue 应用程序。
然而,在 Vue 3 中,初始化代码语法已更改。首先让咱们看一下新语法,而后再看一下应用它的益处。
新的 Vue 3 createApp 办法
在 Vue 3 中,咱们有一个专门的 createApp
函数来实现这一点。createApp 函数以一个根组件 (App.vue
) 作为参数,并返回一个 Vue 利用实例。因而,最简略的利用初始化如下所示:
import {createApp} from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
createApp 返回的 Vue 应用程序实例也称为应用程序上下文对象。这个对象能够用来在疏导过程中进一步为利用增加更多的性能。上面是一个更高级的初始化代码示例:
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import SomeComponent from '@/components/SomeComponent.vue'
import SomePlugin from '@/plugins/SomePlugin'
const myV3App = createApp(App)
myV3App.component('SomeComponent', SomeComponent)
myV3App
.use(SomePlugin)
.use(router)
// add more functionality to myV3App
// now we're ready to mount
myV3App.mount('#app')
与 V2 相比,在增加额定的逻辑(例如插件和组件)方面没有太大变动,对吗?
您能够在 Vue 3 文档中找到受反对办法的残缺概述。
这很好,但有一个小小的但很重要的变动——咱们应用了一个专门的函数,而不是 new Vue
实例。
//v2
const vue2App = new Vue({}) // Working with the main Vue instace
//v3
const myV3App = createApp(App).mount('#app') // Create a copy of the Vue instance
那么,为什么应用新的专用 createApp
函数比应用 new Vue
构造函数更好呢?
Vue 3 初始化代码的益处
在 Vue 2 应用程序初始化代码中,咱们应用了从库中导入的 Vue 对象来创立此应用程序实例以及所有其余新的应用程序实例。
应用这种办法,不可能将一些性能仅隔离到一个 Vue 实例中,因为 Vue 应用程序依然应用从库中导入的同一个 Vue 对象。
为了演示这一点,让咱们看看上面的例子——正如你所看到的,vue2AppOne
和 vue2AppTwo
都能够拜访一个名为 myDirective
的指令:
Vue.directive('myDirective', {/* ... */})
Vue.component({/* ... */})
const vue2AppOne = new Vue(/**/).mount('#app1')
const vue2AppTwo = new Vue(/**/).mount('#app1')
在一个网站或应用程序中创立多个 Vue 应用程序可能并不常见。
但随着我的项目规模的扩充,由不同的团队开发,以及前台微服务的风行,你可能会在某个时候发现自己也在这样做。
而后,简直不可能应用 v2 语法取得另一个具备不同性能的 Vue 实例。
Vue 3 中的新语法容许咱们将每个应用程序的配置作为一个独自的自定义对象,因为应用程序是应用专用函数 (createApp
) 来创立独立实例的。
新的体系结构使咱们能够领有两个或更多孤立的 Vue 实例,默认状况下它们不共享任何个性,即便它们是在一个文件中创立的。
然而,如果你想在两个实例之间共享一些性能,你能够!在上面的例子中,vue3AppOne
和 vue3AppTwo
共享 LocalePlugin
,但不共享 searchchinputcomponent
。
const config = {/* some global config */}
const vue3AppOne = Vue.createApp(config)
vue3AppOne.component('SearchInput', SearchInputComponent)
vue3AppOne.use(LocalePlugin)
const vue3AppTwo = Vue.createApp(config)
vue3AppTwo.use(LocalePlugin)
为了演示这种行为,咱们用 2 个简略的 Vue 3 实例创立了一个代码仓库,因为应用了新的 createApp
语法,这些实例不共享组件和指令。请看一下它在本地的玩法。
在配套的仓库中,咱们在一个页面模板的两个不同容器中初始化了两个 Vue 3 应用程序,见 public/index.html。
<div id="header-app"></div>
<div id="main-app"></div>
一个应用程序将作为一个绝对简略的 header 标记,而另一个将可能应用 router 并与 store 单干。
应用 Vue 3 语法,咱们能够轻松地在 src/main.js 文件的初始化代码中将它们离开:
import {createApp} from 'vue'
import App from './App.vue'
import Header from './Header.vue'
import router from './router'
import store from './store'
createApp(App)
.use(store)
.use(router)
.mount('#main-app')
createApp(Header)
.mount('#header-app')
如果您应用 vue serve
运行应用程序,您应该可能看到两个局部在一个页面上工作。在控制台输入中,您将看到 Main 应用程序能够应用 Vuex
拜访 vue-router
和商店,而 Header 应用程序则不能。
created () {console.log('Hello from Main app')
console.log('Main app router', this.$route)
console.log('Main app store:', this.$store)
}
一个更间接的测试设置
如果您正在应用 vue-test-utils
(版本 <2.0.0)为您的 Vue 2 组件编写测试,您可能会遇到须要应用 createLocalVue
办法来防止净化全局 Vue 实例的状况。
在咱们的测试场景中存在与 Vue 2 应用程序中雷同的潜在问题。当咱们增加组件、插件等时,会净化全局 Vue 实例,而且它们都与每个可用的 Vue 实例共享。
要解决这个问题,咱们必须应用 createlocalvalue
,它 (您曾经猜到了) 创立一个新的孤立的本地 Vue 实例。
import {createLocalVue, mount} from '@vue/test-utils'
import MyPlugin from '@/plugins/MyPlugin'
const localVueForTest = createLocalVue()
localVueForTest.use(MyPlugin)
mount(Component, {localVueForTest})
这在 Vue 3 中不再是一个问题,因为所有的利用扩大:插件、mixins 和全局组件都不会扭转全局 Vue 实例。因而,当在 Vue 3 中应用vue-test-utils
(版本 > = 2.0.0)时,测试文件中的应用程序初始化代码将如下所示:
import {createStore} from 'vuex'
import {mount} from '@vue/test-utils'
import App from '@/App'
import MyPlugin from '@/plugins/MyPlugin'
const wrapper = mount(App, {
global: {plugins: [MyPlugin]
}
})