Vue 3.0 全局API

2021-07-16 11:45 更新

Vue 2.x 有許多全局 API 和配置,這些 API 和配置可以全局改變 Vue 的行為。例如,要創(chuàng)建全局組件,可以使用 Vue.component 這樣的 API:

  1. Vue.component('button-counter', {
  2. data: () => ({
  3. count: 0
  4. }),
  5. template: '<button @click="count++">Clicked {{ count }} times.</button>'
  6. })

類似地,使用全局指令的聲明方式如下:

  1. Vue.directive('focus', {
  2. inserted: el => el.focus()
  3. })

雖然這種聲明方式很方便,但它也會導致一些問題。從技術上講,Vue 2 沒有“app”的概念,我們定義的應用只是通過 new Vue() 創(chuàng)建的根 Vue 實例。從同一個 Vue 構造函數(shù)創(chuàng)建的每個根實例共享相同的全局配置,因此:

  • 在測試期間,全局配置很容易意外地污染其他測試用例。用戶需要仔細存儲原始全局配置,并在每次測試后恢復 (例如重置 Vue.config.errorHandler)。有些 API 像 Vue.use 以及 Vue.mixin 甚至連恢復效果的方法都沒有,這使得涉及插件的測試特別棘手。實際上,vue-test-utils 必須實現(xiàn)一個特殊的 API createLocalVue 來處理此問題:

  1. import { createLocalVue, mount } from '@vue/test-utils'
  2. // 建擴展的 `Vue` 構造函數(shù)
  3. const localVue = createLocalVue()
  4. // 在 “l(fā)ocal” Vue構造函數(shù)上 “全局” 安裝插件
  5. localVue.use(MyPlugin)
  6. // 通過 `localVue` 來掛載選項
  7. mount(Component, { localVue })

  • 全局配置使得在同一頁面上的多個“app”之間共享同一個 Vue 副本非常困難,但全局配置不同。

  1. // 這會影響兩個根實例
  2. Vue.mixin({
  3. /* ... */
  4. })
  5. const app1 = new Vue({ el: '#app-1' })
  6. const app2 = new Vue({ el: '#app-2' })

為了避免這些問題,在 Vue 3 中我們引入...

#一個新的全局 API:createApp

調用 createApp 返回一個應用實例,這是 Vue 3 中的新概念:

  1. import { createApp } from 'vue'
  2. const app = createApp({})

應用實例暴露當前全局 API 的子集,經驗法則是,任何全局改變 Vue 行為的 API 現(xiàn)在都會移動到應用實例上,以下是當前全局 API 及其相應實例 API 的表:

2.x 全局 API 3.x 實例 API (app)
Vue.config app.config
Vue.config.productionTip removed (見下方)
Vue.config.ignoredElements app.config.isCustomElement (見下方)
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use (見下方)

所有其他不全局改變行為的全局 API 現(xiàn)在被命名為 exports,文檔見全局 API Treeshaking。

#config.productionTip 移除

在 Vue 3.x 中,“使用生產版本”提示僅在使用“dev + full build”(包含運行時編譯器并有警告的構建) 時才會顯示。

對于 ES 模塊構建,由于它們是與 bundler 一起使用的,而且在大多數(shù)情況下,CLI 或樣板已經正確地配置了生產環(huán)境,所以本技巧將不再出現(xiàn)。

#config.ignoredElements 替換為 config.isCustomElement

引入此配置選項的目的是支持原生自定義元素,因此重命名可以更好地傳達它的功能,新選項還需要一個比舊的 string/RegExp 方法提供更多靈活性的函數(shù):

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

重要

在 3.0 中,元素是否是組件的檢查已轉移到模板編譯階段,因此只有在使用運行時編譯器時才考慮此配置選項。如果你使用的是 runtime-only 版本 isCustomElement 必須通過 @vue/compiler-dom 在構建步驟替換——比如,通過 compilerOptions option in vue-loader。

  • 如果 config.isCustomElement 當使用僅運行時構建時時,將發(fā)出警告,指示用戶在生成設置中傳遞該選項;
  • 這將是 Vue CLI 配置中新的頂層選項。

#插件使用者須知

插件開發(fā)者通常使用 Vue.use。例如,官方的 vue-router 插件是如何在瀏覽器環(huán)境中自行安裝的:

  1. var inBrowser = typeof window !== 'undefined'
  2. /* … */
  3. if (inBrowser && window.Vue) {
  4. window.Vue.use(VueRouter)
  5. }

由于 use 全局 API 在 Vue 3 中不再使用,此方法將停止工作并停止調用 Vue.use() 現(xiàn)在將觸發(fā)警告,于是,開發(fā)者必須在應用程序實例上顯式指定使用此插件:

  1. const app = createApp(MyApp)
  2. app.use(VueRouter)

#掛載 App 實例

使用 createApp(/* options */) 初始化后,應用實例 app 可用于掛載具有 app.mount(domTarget)

  1. import { createApp } from 'vue'
  2. import MyApp from './MyApp.vue'
  3. const app = createApp(MyApp)
  4. app.mount('#app')

經過所有這些更改,我們在指南開頭的組件和指令將被改寫為如下內容:

  1. const app = createApp(MyApp)
  2. app.component('button-counter', {
  3. data: () => ({
  4. count: 0
  5. }),
  6. template: '<button @click="count++">Clicked {{ count }} times.</button>'
  7. })
  8. app.directive('focus', {
  9. mounted: el => el.focus()
  10. })
  11. // 現(xiàn)在所有應用實例都掛載了,與其組件樹一起,將具有相同的 “button-counter” 組件 和 “focus” 指令不污染全局環(huán)境
  12. app.mount('#app')

#提供/注入 (Provide / Inject)

與在 2.x 根實例中使用 provide 選項類似,Vue 3 應用實例還可以提供可由應用內的任何組件注入的依賴項:

  1. // 在入口
  2. app.provide('guide', 'Vue 3 Guide')
  3. // 在子組件
  4. export default {
  5. inject: {
  6. book: {
  7. from: 'guide'
  8. }
  9. },
  10. template: `<div>{{ book }}</div>`
  11. }

#在應用之間共享配置

在應用之間共享配置 (如組件或指令) 的一種方法是創(chuàng)建工廠功能,如下所示:

  1. import { createApp } from 'vue'
  2. import Foo from './Foo.vue'
  3. import Bar from './Bar.vue'
  4. const createMyApp = options => {
  5. const app = createApp(options)
  6. app.directive('focus' /* ... */)
  7. return app
  8. }
  9. createMyApp(Foo).mount('#foo')
  10. createMyApp(Bar).mount('#bar')

現(xiàn)在,F(xiàn)oo 和 Bar 實例及其后代中都可以使用 focus 指令。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號