为naive-ui添加全局的message函数
前言
为 naive-ui 添加全局的 message ,notification , loaddingBar , dialog 函数
对于 Vue3 ,个人非常喜欢 naive-ui 这个 ui 库,并且也在工作中把它应用到了相应的项目之中
虽然它看起来有点像 ant-design , 不过国内的 ui 库大体都是以蓝色为主色,看起来就有些审美疲劳了
正文
我们都知道,像 element-ui , ant-design 等都有一些通用的方法可供全局使用,即可以脱离组件的上下文
比如 element-plus 的
我们可以在任何地方使用这些组件,比如 axios 的拦截器中,或者路由守卫( hooks )中
而在 naive-ui 中,使用 message 的方法比较特别
首先是必须包在 n-message-provider 组件下
然后使用 useMessage 来获取 message 实例
App.vue
1 | <script setup lang="ts"> |
Content.vue
1 | <script setup lang="ts"> |
看起来有点复杂
我去翻了下历史的 issues 记录, 发现有人已经有提过相关的 issue 了
不过作者似乎并不想提供这样的 api ,作者在第三个 issue 中回复了
If you must need to render a message before app is ready, you need to render a app outside current app and set message api globally. However remember message is a part of your app. You can’t operate a phone before you turn it on.
意思是如果确实需要在 app 被挂在前调用 message, 那么需要在原 app 外部额外渲染一个 app ,并且把相关的 api 全局化
作者的意思很简单,想用 message, 就是得 app 挂载了才能用,因为 message 就是整个 app 的一个部分
作者还举了个例子:你不能在手机还没开机的时候就操作它
所以,我们需要按照作者说的来进行 hack
干掉 useXXX
每次都要 useMessage 很麻烦,那么如何才能导出一个全局变量呢?
可以通过添加一个空的组件来把 message 提升到全局
MessageInjectWindow.vue
1 | <script setup lang="ts"> |
然后我们把上面的组件放到 App.vue 中
1 | <script setup lang="ts"> |
然后在 Content.vue 中就可以使用 $message 了
1 | <script setup lang="ts"> |
不过在代码的过程中总觉得缺了点啥?没错,就是代码提示
这是一个 ts 的项目,通过添加 d.ts 可以为 $message 赋予类型提示
创建 global.d.ts 然后输入以下内容
1 | declare global { |
在 Window 下定义是因为需要通过 window['$xxx'] = useXXX() 来挂载, 不加的话在 ts 项目下就会有红线
在 global 下定义意味着除了 window['$xxx'] 来调用之外,也可以直接使用 $xxx 直接使用
这样子代码就有不错的提示了


干掉只能在app内使用
虽然我们已经提取了全局的 api 了,但是依然无法在没有 app 的上下文下使用
比如如果我想在 mount 之前调用一个接口,这个接口要使用 message 来显示一些信息,那么就会报错
1 | import { createApp } from "vue"; |
结果显而易见,报错

原因很简单,都没挂载 app ,那么 MessageInjectWindow.vue 的 setup 不会执行,自然也就没有注入 message 实例了
那么这时候就需要构建一个空的 app ,在目标 app 之前挂载,然后全局化 api
创建 AppProvider.vue
1 | <script lang="ts" setup> |
内容基本一样,不过没有 Content.vue ,因为作为一个空的 app ,不需要渲染真正的内容节点
然后修改 main.ts
1 | import { createApp } from "vue"; |
然后就可以愉快的使用全局的 $message 了
后记
这个方法是从 Naive-ui-admin 以及相关的 issues 查找到的
目前已经用在公司的项目中
如果只是讨厌每次调用接口时写 useXXX
issues 中也有用户提议可以封装通用的 useRequest
反正,萝卜青菜各有所爱吧~