新的Vue 3 應(yīng)用程序初始化代碼的好處
在這篇文章中,我們將首先看看Vue 2應(yīng)用程序中的應(yīng)用程序初始化代碼是如何工作的。然后我們會看到它有哪些缺點,以及如何通過Vue框架第3版中使用的新初始化語法消除這些缺點。
我們先說說目前Vue 2中的初始化方式。通常,在 src/main.js 文件中,我們是通過調(diào)用一個新的Vue作為創(chuàng)建應(yīng)用實例的構(gòu)造函數(shù)來引導(dǎo)應(yīng)用的。
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')
這個應(yīng)用實例將在我們SPA的整個生命周期內(nèi)為所有的邏輯服務(wù)。這一切都很好,大約3年來,我們一直使用這種語法來引導(dǎo)我們的Vue應(yīng)用程序。
但是,在Vue 3中,初始化代碼語法已更改。首先讓我們看一下新語法,然后再看一下使用它的好處。
新的Vue 3 createApp方法
在Vue 3中,我們有一個專門的 createApp 函數(shù)來實現(xiàn)這一點。createApp函數(shù)以一個根組件(App.vue)作為參數(shù),并返回一個Vue應(yīng)用實例。因此,最簡單的應(yīng)用初始化如下所示:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
createApp返回的Vue應(yīng)用程序?qū)嵗卜Q為應(yīng)用程序上下文對象。這個對象可以用來在引導(dǎo)過程中進一步為應(yīng)用添加更多的功能。下面是一個更高級的初始化代碼示例:
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相比,在添加額外的邏輯(例如插件和組件)方面沒有太大變化,對嗎?
這很好,但有一個小小的但很重要的變化——我們使用了一個專門的函數(shù),而不是 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 函數(shù)比使用 new Vue 構(gòu)造函數(shù)更好呢?
Vue 3初始化代碼的好處
在Vue 2應(yīng)用程序初始化代碼中,我們使用了從庫中導(dǎo)入的Vue對象來創(chuàng)建此應(yīng)用程序?qū)嵗约八衅渌碌膽?yīng)用程序?qū)嵗?/p>
使用這種方法,不可能將一些功能僅隔離到一個Vue實例中,因為Vue應(yīng)用程序仍然使用從庫中導(dǎo)入的同一個Vue對象。
為了演示這一點,讓我們看看下面的例子——正如你所看到的,vue2AppOne 和 vue2AppTwo 都可以訪問一個名為 myDirective 的指令:
Vue.directive('myDirective', {
/* ... */
})
Vue.component({
/* ... */
})
const vue2AppOne = new Vue(/**/).mount('#app1')
const vue2AppTwo = new Vue(/**/).mount('#app1')
在一個網(wǎng)站或應(yīng)用程序中創(chuàng)建多個Vue應(yīng)用程序可能并不常見。
但隨著項目規(guī)模的擴大,由不同的團隊開發(fā),以及前臺微服務(wù)的流行,你可能會在某個時候發(fā)現(xiàn)自己也在這樣做。
然后,幾乎不可能使用v2語法獲得另一個具有不同功能的Vue實例。
Vue 3中的新語法允許我們將每個應(yīng)用程序的配置作為一個單獨的自定義對象,因為應(yīng)用程序是使用專用函數(shù)(createApp)來創(chuàng)建獨立實例的。
新的體系結(jié)構(gòu)使我們可以擁有兩個或更多孤立的Vue實例,默認(rèn)情況下它們不共享任何特性,即使它們是在一個文件中創(chuàng)建的。
然而,如果你想在兩個實例之間共享一些功能,你可以!在下面的例子中,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實例創(chuàng)建了一個代碼倉庫,由于使用了新的 createApp 語法,這些實例不共享組件和指令。請看一下它在本地的玩法。
在配套的倉庫中,我們在一個頁面模板的兩個不同容器中初始化了兩個Vue 3應(yīng)用程序,見public/index.html。
<div id="header-app"></div>
<div id="main-app"></div>
一個應(yīng)用程序?qū)⒆鳛橐粋€相對簡單的header標(biāo)記,而另一個將能夠使用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 運行應(yīng)用程序,您應(yīng)該能夠看到兩個部分在一個頁面上工作。在控制臺輸出中,您將看到Main應(yīng)用程序可以使用 Vuex 訪問 vue-router 和商店,而Header應(yīng)用程序則不能。
created () {
console.log('Hello from Main app')
console.log('Main app router', this.$route)
console.log('Main app store:', this.$store)
}
一個更直接的測試設(shè)置
如果您正在使用 vue-test-utils(版本<2.0.0)為您的Vue 2組件編寫測試,您可能會遇到需要使用 createLocalVue 方法來避免污染全局Vue實例的情況。
在我們的測試場景中存在與Vue 2應(yīng)用程序中相同的潛在問題。當(dāng)我們添加組件、插件等時,會污染全局Vue實例,而且它們都與每個可用的Vue實例共享。
要解決這個問題,我們必須使用 createlocalvalue,它(您已經(jīng)猜到了)創(chuàng)建一個新的孤立的本地Vue實例。
import { createLocalVue, mount } from '@vue/test-utils'
import MyPlugin from '@/plugins/MyPlugin'
const localVueForTest = createLocalVue()
localVueForTest.use(MyPlugin)
mount(Component, {
localVueForTest
})
這在Vue 3中不再是一個問題,因為所有的應(yīng)用擴展:插件、mixins和全局組件都不會改變?nèi)諺ue實例。因此,當(dāng)在Vue 3中使用vue-test-utils(版本> = 2.0.0)時,測試文件中的應(yīng)用程序初始化代碼將如下所示:
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]
}
})
作者:Mikhail Kuznetsov
最近文章
使用 Face-api.js 在 Web 上進行人臉檢測 如何檢測 JavaScript 字符串中的 URL 并將其轉(zhuǎn)換為鏈接? 開發(fā)App新選擇:使用 Vue Native 構(gòu)建移動應(yīng)用 5 個可以加速開發(fā)的 VueUse 庫函數(shù) Vue 中使用defineAsyncComponent 延遲加載組件 使用React Native可以開發(fā)Window桌面應(yīng)用了! 黑客說:如何做到 4 天上線一個小程序? 2021年加速App開發(fā)的8個最佳跨平臺框架
