如何更优雅地为naive-ui的useMessage扩展全局方法

背景

最近做了一个埋点需求,要求 message 做成统一的成功与失败上报,就是在某个功能 success 的时候,同时上报对应的成功信息,否则上报失败。

技术方案

方案一

在 项目的 utils 里面封装一个 reportMessage(reportError 同理),然后要用到的地方就用类似方法调用:

ts 复制代码
// utils
export const reportSuccess = (reportMessageArg, options) => {
  reportMessage({ ...reportMessageArg, type: 'success' });
  const message = useMessage()
  return message.success(reportMessageArg.msg, options)
}

// 其他用到的地方
import { reportSuccess } from 'utils'

reportSuccess({...})

这样确实能解决问题,但是如果你要用到 message 自带的方法,就得 import { useMessage } from 'naive-ui',如果要用到 report 上报,就得用到 import { reportSuccess, reportError } from 'utils',这样显得相当麻烦,且其他人以后有 message 上报的需求,不一定知道你写了这些方法。

方案二

因为 useMessage 返回的是对象,所以可以很好地利用对应的引用类型给其添加方法

ts 复制代码
import { useMessage } from 'naive-ui'
import { reportMessage } from '@utils'

// 给 message 添加 上报的 success 和 error 方法

export const useExtendMessage = () => {
  const message = useMessage()

  message.reportSuccess = (reportMessageArg, options) => {
    reportMessage({ ...reportMessageArg, type: 'success' })
    return message.success(reportMessageArg.msg, options)
  }

  message.reportError = (reportMessageArg, options) => {
    reportMessage({ ...reportMessageArg, type: 'error' })
    return message.error(reportMessageArg.msg, options)
  }

  return message
}

对的,你没看出,就是这么简单,但可能你会很好奇,为何这样就能全局生效?不会要我其他地方得通过import { useExtendMessage } from '@hooks'吧?,那不还是一样。。。

不是的,你还是通过import { useMessage } from 'naive-ui',但是这时候得到的 message 就自动有了reportSuccessreportError 方法,且听我一一道来~

方案二探索过程

添加两个方法

点进去 node_modules,发现 useMessage 就只是通过 inject 一个 key 来获取 message 实例:

再找到注入 messageApiInjectionKey 的地方,发现是 MessageProvider

也就是 useMessage 要起作用,必须在顶层 template 使用到 NMessageProvider(注意这句话!注意这句话!注意这句话!),类型这样:

那么可以考虑在 NMessageProvider 子组件最近的一级再架一层:

在 ExtendMessageProvider 里面 useMeesage,然后对得到的 message 实例添加方法:

这样也就实现的其他地方用到的 useMessage 得到的 message 有 reportSuccess,reportError 方法了。

全局类型提示

但是!!这时候的 useMeesage 还是没有以上两个 report 的类型:

所以还要在 global.d.ts 里面添加全局声明,而因为 MessageApiInjection 是从naive-ui/es/message/src/MessageProvider 里面 import 的:

所以我们通过declare module 'naive-ui/es/message/src/MessageProvider'加上两个类型:

这样,再通过 useMeesage 得到的 message 就有类型了:

然后我们在 Child 组件里面 log 下 message:

发现在代码层面上也成功加上了方法!!

总结

当接到类似需求时,我们当然可以像【方案一】一样,三下两除二给解决掉,但问题在于不通用(虽然代码确实能跑,哈哈 🤣),但我个人觉得,还是多花费几分钟思考一下,是否有更好的方案,是否能做的更通用些。

然后我们就利用了 vue 的 provide 与 inject,且利用了 js 对象的引用类型功能(你刚学js的时候肯定知道)实现了扩展 message 的功能。

但加上功能并不意味着完成,我们还得考虑下如何提供更好的开发体验,也就是要加上类型,使得其他地方还是通过import { useMessage } from 'naive-ui',但这时候得到的 message 既支持功能,又支持类型提示!

最后

以上只是以 naive-ui 扩展 useMessage 为例子代入,但是不局限于 naive-ui,或者 antd 之类的ui组件库,也不局限 vue 还是 react,本文只是提供了一种解决问题的思路,如果有遇到其他类似场景,希望能对你有所帮助~

相关推荐
飞的肖3 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案111 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_7482548815 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.27 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营31 分钟前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_851 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特1 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
m0_748236112 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust