Vue 3.0 全局API

2021-07-16 11:45 更新

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

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

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

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

雖然這種聲明方式很方便,但它也會導致一些問題。從技術上講,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 來處理此問題:

import { createLocalVue, mount } from '@vue/test-utils'


// 建擴展的 `Vue` 構造函數(shù)
const localVue = createLocalVue()


// 在 “l(fā)ocal” Vue構造函數(shù)上 “全局” 安裝插件
localVue.use(MyPlugin)


// 通過 `localVue` 來掛載選項
mount(Component, { localVue })

  • 全局配置使得在同一頁面上的多個“app”之間共享同一個 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 現(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ù):

// before
Vue.config.ignoredElements = ['my-el', /^ion-/]


// after
const app = Vue.createApp({})
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)境中自行安裝的:

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

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

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

#掛載 App 實例

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

import { createApp } from 'vue'
import MyApp from './MyApp.vue'


const app = createApp(MyApp)
app.mount('#app')

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

const app = createApp(MyApp)


app.component('button-counter', {
  data: () => ({
    count: 0
  }),
  template: '<button @click="count++">Clicked {{ count }} times.</button>'
})


app.directive('focus', {
  mounted: el => el.focus()
})


// 現(xiàn)在所有應用實例都掛載了,與其組件樹一起,將具有相同的 “button-counter” 組件 和 “focus” 指令不污染全局環(huán)境
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>`
}

#在應用之間共享配置

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

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')

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號