方式一:通过组件实例
getCurrentInstance
查阅 Vue 3 官网 API 可以发现这个函数,可以用在 setup 或 生命周期函数 中,以获取当前组件实例(也就是组件内常用的 this ),通过这个函数返回的对象,可以访问我们整个 app 的全局属性:
setup() {
// 组件实例
const myComponentInstance = getCurrentInstance();
// 全局属性
const myAppGlobalProperties = myComponentInstance.appContext.config.globalProperties;
// 后续可以将实例中的函数、方法挂载到全局属性上
}
这种方式获取的 globalProperties 和 app.config.globalProperties 是一样的,因此可以在组件实例中添加更多的全局属性。
实践
我们可以制作一个消息弹窗的组件,在根组件(App.vue)上使用,这样后续的其他子组件内部就可以直接调用 this.$message 显示消息弹窗了。
// MessageBox.vue
<template>
<teleport to="body">
<div v-if="visible" class="message-box">消息弹窗</div>
</teleport>
</template>
<script>
import { ref, getCurrentInstance, defineComponent } from 'vue';
export default defineComponent({
name: 'MessageBox',
setup() {
// 弹窗是否可见
const visible = ref(false);
/**
* 打开弹窗
*/
const open = () => {
visible.value = true;
// 5秒后关闭
setTimeout(() => {
visible.value = false;
}, 5000);
};
// 获取组件实例,挂载全局函数
const instance = getCurrentInstance();
instance.appContext.config.globalProperties.$message = open;
return {
visible
};
},
});
</script>
<style>
.message-box {
position: fixed;
left: 50vw;
top: 50vh;
transform: translate(-50%, -50%);
background: red;
z-index: 9999999999;
}
</style>
方式二:通过插件
这种方式参照Element-plus的el-message实现,使用vue.render函数。
import * as Vue from 'vue';
import Message from './components/Message.vue';
const msg = (text) => {
// 真实DOM,用来挂载VNode
const container = document.createElement('div');
document.body.append(container);
// 创建一个组件,也可以直接 import 一个 *.vue 文件
const vm = Vue.defineComponent({
setup() {
// 返回一个 render 函数
return () => {
return Vue.h('div', null, text);
};
}
});
// 将 vm 渲染到真实 DOM 上
vue.render(vm, container);
};
export default {
install(app) {
app.config.globalProperties.$message = msg;
}
}