全域註冊的方法,意思是每個 Vue 元件都能使用的方法。在 Vue 2 會有以下方法:
Vue.prototype
Vue 3 同樣有以上方法,但注意是語法會有點不同。主要是不再在 Vue 的原型上建立,而是在 app 上建立,因此,你會發現以前的 Vue.mixin() 現在改為 app.mixin(),或者 Vue.use() 改為 app.use()等等。另外,Vue 3 也新增了 provide 和 inject,作用可取代 app.config.globalProperties,即是 Vue 2 的 Vue.prototype。
這不是常見面試題,但想藉此整理自己對全域註冊方法的理解,因此以下會再詳細說明這些語法和使用情景。
避免直接在全域建立變數或函式,我們可以在 Vue 的原型上註冊,並在每個 Vue 實例裏使用。如果幾乎每個元件都會用到此方法的話,此手法會比 mixin 方便,因為不用寫 import xxx from ... 然後又寫一行 mixins: [...]。
看看 Vue 官方例子:
main.js
import Vue from 'vue'
import App from './App.vue'
...
// 定義全域變數
Vue.prototype.$username = 'Alysa'
// 定義全域函式
Vue.prototype.$reverseText = function (propertyName) {
  this[propertyName] = this[propertyName]
    .split('')
    .reverse()
    .join('')
}
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
在元件裏使用:
export default {
  data() {
    return {
      // 使用全域變數
      username: this.$username
    }
  },
  created() {
    // 使用全域函式
    this.$reverseText('username')
    console.log(this.username) // asylA
  }
}
要注意:
undefined 的錯誤。$ 符號代表全域變數或方法。稍為解釋第一點,因為 this 需要指向 Vue 實體,否則取不到資料。箭頭函式會繼承上一層函式所指向的 this。相反,傳統函式的 this 會取決於呼叫的物件,因此當我們在 created 裏呼叫 this.$reverseText,$reverseText 裏的 this 就會指向 Vue 實體。
官方還有舉例一個實際常見用法:在全域註冊 axios 方法。
main.js
import axios from 'axios'
Vue.prototype.$http = axios
再在某元件使用:
created() {
    this.$http('https://randomuser.me/api/')
    .then( res => console.log(res.data)) // {results:...}
}
這樣每次開發時就不用下載 vue-axios 這種插件了,反正自己寫幾行就搞定了。
使用 Vue.prototype 的缺點是,當你是團隊開發,可能有些開發者不太熟 Vue,以為 this.$xxx 全都是 Vue 本身的方法,例如是 this.$http 這樣的寫法,會讓人誤會是 Vue 本身的方法。
除了載入第三方插件,我們也可以建立自己的 plugin。有幾點要注意:
new Vue ({}) 前使用 Vue.use() 載入 plugin。使用 Vue CLI 時,我之前在這個教學影片學習過的做法是,先建立一個叫 libs 的資料夾,裏面再開一個資料夾 MyPlugin,並且建立 index.js 檔案。
src/ libs/ MyPlugin/ index.js
let MyPlugin = {}
// 需要使用 install 方法
MyPlugin.install = function(Vue, options) {
    // 注意!不能在 new Vue() 後使用這些方法
    Vue.greeting = function () {
        console.log('來自 plugin 的 message')
    }
    // 建立指令
    Vue.directive('greeting', {
        bind(el, binding, vnode, oldVnode) {
            console.log('來自 plugin 的 directive')
        }
    })
    // 建立 mixin
    Vue.mixin({
        created() {
            console.log('來自 plugin 的 mixin')
        }
    })
    // 使用 Vue prototype
    Vue.prototype.$greeting = function() {
        console.log('來自 plugin 的 $greeting 方法')
    }
}
export default MyPlugin
再在 main.js 引入此 plugin:
import MyPlugin from '@/libs/MyPlugin'
Vue.use(MyPlugin)
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
注意,在 plugin 裏使用Vue.xxx 註冊的方法,無法在建立 Vue 實體,即是 new Vue() 之後使用。因此無法在元件使用。否則會報錯:
created() {
    this.greeting()
}
// this.greeting is not a function
以上明顯看到,plugin 比第一個提到的方法更強大,可以同時在裏面使用 Vue.prototype、mixin、directive。就如字面 plugin 的意思一樣,此做法通常是用來開發插件時會用到。
相信大家對 mixin 都不陌生了,在此就不累贅重複。簡單講,mixin 的作用就把重用的功能抽出來,讓我們在不同元件裏,可以重用此功能。
最常見做法是,把會重用的功能拆出來,獨立成為一個 JS 檔案,然後把裏面的程式碼 export 出去。最後在元件裏把它 import 進來。
一個常用到的例子,就是當打 API 出錯時,就會彈跳出 error。
mixins/ showAlert.js
export default {
    methods: {
        showError() {
            alert('載入資料失敗')
        }
    },
}
Home.vue 裏使用 showAlert 這個 mixin
import showAlert from '@/mixins/showAlert.js'
export default {
  // 引入 mixin
  mixins: [showAlert],
  created() {
    this.showError()
  }
}
以上看到,在 Home.vue 裏,即使沒有建立 showError 這個 methods,但我們透過 mixins,把 showError 這個函式,合併到 Home.vue 的 methods 裏,因此 Home.vue 現在其實是這樣:
export default {
  methods: {
      showError() {
        alert('載入資料失敗')
      }
  }
  created() {
    this.showError()
  }
}
除了 methods,也可以用 data、created、mounted 等,如同寫 Vue 元件時一樣。
跟 Vue.prototype 的效果一樣,如果全域註冊 mixin的話,每個元件都會用到此 mixin,不用每次都要自行 import 進來才用到。
main.js
Vue.mixin({
  methods: {
      showError() {
        alert('載入資料失敗')
      }
  }
})
升級到 Vue 3 後,現在是使用 createApp() 來建立 Vue 應用程式,因此不再把全局方法註冊在 Vue 身上,而是在 app 上建立。
import { createApp } from 'vue'
const app = createApp({})
截圖自官方文件:

以前 Vue 2 是直接在 Vue 的原型上使用這些全域 API,即是 Vue.use()、Vue.mixin()。因此會出現 Vue 實體被污染的情況,因為所有 Vue 實體都是由 new Vue() 此建構函式來建立,因此每一個實體也有共享了這些全域方法。
官方說明:
// 这会影响到所有根实例
Vue.mixin({
  /* ... */
})
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
為了避免此問題,Vue 使用了 createApp 的手法來建立 Vue 的實體,而所有全域註冊的 mixin、plugin 等,全都會在該 app 上,而不是 Vue 原型上。
所以,當你建立一個 Vue CLI 專案時,你會發現 router 是註冊在某個 app 上。
const { createApp } = Vue
const app = createApp({})
app.use(router).mount('#app')
除了以上的變更,Vue 3 新增了 provide / inject 語法,官方更表示可以代替使用 app.config.globalProperties。
通常我們會在跨元件傳資料時,才會用到 provide 和 inject,但其實同樣可以用來實現全域註冊:
main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.provide('message', function() {
    console.log('來自全域的 provide')
})
app.use(router).mount('#app')
Home.vue
export default {
  inject: {
    msg: {
      from: 'message'
    }
  },
  created() {
    this.msg() // 來自全域的 provide
  }
}
這應該是相對常用的方法,特別是跨元件傳資料時就非常方便。不用一直不斷用 props 往下傳資料。
舉例說: Home --> ProductInfo --> ProductComments。
要把在 Home 的資料傳到 ProductComments。
Home.vue
export default {
  ...,
  data() {
    return {
      comments: ['Nice product', 'Cool!']
    }
  },
  provide() {
    return {
      comments: this.comments
    }
  }
}
ProductComments.vue
export default {
    inject: ['comments'],
    created() {
        console.log(this.comments) // ['Nice product', 'Cool!']
    }
}
Vue.prototype、plugin 和 mixin 全域註冊方法。Vue3 的資料狀態管理,provide / inject、vuex、props
Global API
Vue中如何使用插件?(Plugins)【Vue面试题】