为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
反正,萝卜青菜各有所爱吧~