全域注册的方法,意思是每个 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面试题】
<<: 第 22 集:Bootstrap 客制化 utilities(下)
>>: 追求JS小姊姊系列 Day22 -- 工具人、姐妹不只身份的差别(中):从识别字开始讲起吧
在介绍react实例之前,首先来介绍一下其操作原理---Virtual DOM,并比较和Actual...
前言 在 macOS 我使用 Clipy 来管理我的剪贴簿,它不但可以储存你所复制过的东西还可以自订...
我最早开始使用委派 是在开发游戏功能的时候 当时有个需求是需要写一个角色升级的功能 (当年是个人吃人...
抱歉惹,最近实在太累,上一个系列对我来说资讯量有点庞大,看了很久才搞懂内容是什麽,每天上班玩回来看个...
超时空跑马灯 ( 广播 ) 教学原文参考:超时空跑马灯 ( 广播 ) 这篇文章会介绍如何使用「发送数...