ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 gin-vue-admin 前端工具函数全景指南src/utils 复用规范与源码级解析【免费下载链接】gin-vue-adminViteVue3Gin拥有AI辅助的基础开发平台企业级业务AI开发解决方案内置mcp辅助服务内置skills管理支持TS和JS混用。它集成了JWT鉴权、权限管理、动态路由、显隐可控组件、分页封装、多点登录拦截、资源权限、上传下载、代码生成器、表单生成器和可配置的导入导出等开发必备功能。项目地址: https://gitcode.com/gh_mirrors/gi/gin-vue-admin导读gin-vue-adminGVA的前端工程在web/src/utils/目录下沉淀了一套覆盖 HTTP 请求、日期与字典格式化、路由权限、图片处理、跨组件通信等场景的工具函数库。本文以项目内 aiDoc/frontend-backend/frontend-utils.md 中定义的“复用优先”约束为骨架逐一解读每个工具的职责边界、调用方式与底层实现原理帮助开发者在编写业务代码时快速定位正确工具、避免重复造轮子并理解这些工具背后的设计考量。一、核心原则复用优先严禁重复造轮子aiDoc/frontend-backend/frontend-utils.md开篇即明确了前端开发的铁律开发任何前端功能前必须优先检查并复用src/utils/下已有能力严禁重复造轮子。这条约束并非空话它直接决定了 GVA 业务代码的编写习惯在动手写一个新的请求封装、日期格式化函数或 UUID 生成器之前先到web/src/utils/目录确认是否已有现成实现。项目内 前端与后端边界文档 对前端职责划分的约定也与“工具收敛、逻辑沉淀”的思路一致。这样做的好处体现在三方面行为一致全局统一的请求拦截、错误提示、loading 管理避免各页面各自为政维护集中修复一个 bug 只需改动一处例如 token 刷新逻辑、loading 强制关闭策略降低心智负担新成员通过阅读工具目录即可掌握项目的前端基础设施能力。下文按功能域对工具逐一展开并给出对应的源码位置供深入查阅。二、HTTP 请求统一入口request.js文件位置web/src/utils/request.jsrequest.js是基于 axios 二次封装的唯一请求出口也是整个前端数据链路的主动脉。所有 HTTP 请求必须经过它对应文档“强制使用场景”第一条。2.1 请求拦截器做了什么请求发出前拦截器依次完成四件事默认超时若调用方未显式指定timeout统一设置DEFAULT_REQUEST_TIMEOUT 1000 * 60 * 1010 分钟Loading 管理除非配置donNotShowLoading: true否则调用showLoading展示全局加载态并通过activeAxios计数支持多请求并发下的正确关闭baseURL 注入config.baseURL config.baseURL || import.meta.env.VITE_BASE_API开发/生产环境由 Vite 环境变量接管认证头注入从useUserStore读取 token 与用户 ID写入x-token、x-user-id请求头这是后端 JWT 鉴权见 middleware/jwt.go的前端侧配合点。// 典型业务用法来自源码拦截器行为 import request from /utils/request export const getUserList (params) request({ url: /user/list, method: get, params }) // 不需要全局 loading 时 export const silentRequest () request({ url: /api/x, method: post, data, donNotShowLoading: true })2.2 响应拦截器的分层处理响应处理是request.js中最复杂的部分按优先级拆解如下新 token 刷新响应头携带new-token时自动写入用户 store实现无感续期统一结果判断response.data.code 0或响应头success true视为成功直接返回response.data业务层无需再解包错误消息去重showErrorMessage用activeErrorMessagesMap 记录正在展示的错误相同内容不重复弹出且同时最多展示 3 条防止批量请求失败时刷屏HTTP 状态码分流401触发emitter.emit(show-error, ...)在回调中清空本地存储并跳转登录页强制改密命中isPasswordChangeRequiredError见 web/src/utils/requestError.js时跳转ForceChangePassword页面网络层错误无error.response重置 loading 并广播network错误事件异常兜底页面beforeunload/unload时调用resetLoading避免页面关闭后残留全局 loading。2.3 Loading 的延迟与强制关闭策略源码中有两个值得注意的细节showLoading并非立即弹 loading而是延迟400ms才展示短请求不会闪烁加载层若 loading 已展示但请求超过DEFAULT_LOADING_FORCE_CLOSE_DELAY 30000ms未结束会触发scheduleForceClose强制关闭并告警防止接口长时间挂起导致 UI 卡死。三、格式化三件套date.js、format.js、stringFun.js3.1date.js日期格式化文件位置web/src/utils/date.js该文件通过扩展Date.prototype.Format提供类似 .NET 的占位符格式化语法占位符规则如下占位符含义说明yyyy/yy年份1–4 个占位符M/MM月份1–2 个占位符M不补零d/dd日1–2 个占位符h/hh小时1–2 个占位符m/mm分钟1–2 个占位符s/ss秒1–2 个占位符q季度1–2 个占位符S毫秒仅 1 个占位符// 源码注释中的示例 (new Date()).Format(yyyy-MM-dd hh:mm:ss.S) // 2006-07-02 08:09:04.423 (new Date()).Format(yyyy-M-d h:m:s.S) // 2006-7-2 8:9:4.18同时导出formatTimeToStr(times, pattern)不传 pattern 时默认输出yyyy-MM-dd hh:mm:ss常用于列表时间列。3.2format.js常用格式化能力集文件位置web/src/utils/format.js这是文档点名的“布尔值、字典、URL、主题色、UUID 等常用格式化”工具核心导出函数函数能力说明formatBoolean(bool)布尔值 → 中文true→是false→否null→formatDate(time)时间 → 字符串底层委托formatTimeToStrfilterDict(value, options)字典值 → 标签递归查找支持树形字典filterDataSource(dataSource, value)数据源 → 标签支持传数组批量映射为标签数组getDictFunc(type)异步取字典薄封装getDictReturnArrImg(arr)图片路径拼接底层调用getUrl支持单值与数组onDownloadFile(url)新窗口打开文件window.open(getUrl(url))getBaseUrl()获取接口 baseURLVITE_BASE_API /时返回空串CreateUUID()生成 UUID以时间戳 performance.now()为随机种子其中CreateUUID是文档“强制使用场景”点名的函数export const CreateUUID () { let d new Date().getTime() if (window.performance typeof window.performance.now function) { d performance.now() } return 00000000-0000-0000-0000-000000000000.replace(/0/g, (c) { const r (d Math.random() * 16) % 16 | 0 d Math.floor(d / 16) return (c 0 ? r : (r 0x3) | 0x8).toString(16) }) }注意filterDict与filterDataSource都实现了children 递归查找这意味着即使字典是树形结构父字典含子字典也能从任意层级反查标签与 pinia/modules/dictionary.js 的树形字典数据模型完全匹配。3.3stringFun.js命名格式转换文件位置web/src/utils/stringFun.js主要服务于前后端字段命名对齐Go 侧惯用驼峰/下划线四个函数toUpperCase(name) // Name 首字母大写 toLowerCase(Name) // name 首字母小写 toSQLLine(userName) // user_name 驼峰转下划线 toHump(user_name) // userName 下划线转驼峰toSQLLine对ID做了特殊保护直接返回原值避免全大写缩写被错误拆分成_i_d。四、字典与系统参数dictionary.js、params.js4.1dictionary.js字典数据获取文件位置web/src/utils/dictionary.js文档“强制使用场景”明确获取字典数据时必须优先使用/utils/dictionary。核心函数import { getDict } from /utils/dictionary // 获取完整字典树 const dictTree await getDict(user_status) // 获取指定深度的扁平化数据depth2 即取到第 2 层后扁平化 const dictFlat await getDict(user_status, { depth: 2 }) // 获取指定 value 节点的 children const children await getDict(user_status, { value: active })底层数据流getDict参数校验后调用 pinia/modules/dictionary.js 的getDictionary该 store 内部优先调用getDictionaryTreeListByType获取树形字典通过filterTreeByDepth按深度裁剪、flattenTree扁平化、normalizeTreeData标准化字段label/value/extend/children树形接口不可用时回退到findSysDictionary的平铺格式所有结果按type_value_${value}_depth_${depth}或type_tree/type_depth_${depth}规则缓存进dictionaryMap同参数二次获取零网络请求。配套的showDictLabel(dict, code, keyCode, valueCode)用于将字典数组映射为value → label的查找表是表格列渲染中文标签的常用辅助。4.2params.js系统参数获取文件位置web/src/utils/params.jsimport { getParams } from /utils/params // 异步获取系统参数源码注释中的推荐用法 const res ref() const fun async () { res.value await getParams(test) } fun()底层由 pinia/modules/params.js 的useParamsStore支撑getParams(key)先查paramsMap缓存未命中再调用getSysParam({ key })并写入缓存。系统参数对应后端 sys_params.go 维护的键值配置适用于开关类、阈值类的全局配置项。五、路由与权限域asyncRouter.js、btnAuth.js、fmtRouterTitle.js、page.js5.1asyncRouter.js动态路由组件解析文件位置web/src/utils/asyncRouter.jsGVA 的菜单/路由由后端下发字符串形式的 component 路径前端负责把字符串解析为真实组件const viewModules import.meta.glob(../view/**/*.vue) const pluginModules import.meta.glob(../plugin/**/*.vue) export const asyncRouterHandle (asyncRouter) { asyncRouter.forEach((item) { if (item.component typeof item.component string) { item.meta.path /src/ item.component if (item.component.split(/)[0] view) { item.component dynamicImport(viewModules, item.component) } else if (item.component.split(/)[0] plugin) { item.component dynamicImport(pluginModules, item.component) } } if (item.children) { asyncRouterHandle(item.children) // 递归处理子路由 } }) }关键设计使用import.meta.glob预构建 view 与 plugin 的组件映射当数据库菜单指向的组件已不存在时返回一个MissingComponentPlaceholder占位组件而非undefined从源码注释看这是为了避免路由白屏常见于历史遗留菜单记录。该函数在 web/src/router/index.js 的权限路由生成流程中被调用。5.2btnAuth.js按钮级权限文件位置web/src/utils/btnAuth.js文档“强制使用场景”要求按钮权限必须使用useBtnAuthimport { useBtnAuth } from /utils/btnAuth const btnAuth useBtnAuth() // 用法示例视图中 if (btnAuth.add) { /* 显示新增按钮 */ }实现极简——直接读取当前路由route.meta.btns与后端下发的按钮权限元数据对应路由 meta 中由权限系统注入按钮标识未配置时返回空响应式对象。5.3fmtRouterTitle.jspage.js页面标题文件位置web/src/utils/fmtRouterTitle.js、web/src/utils/page.jsfmtTitle(title, now)支持在路由标题中嵌入${param}占位符运行时用路由 params 或 query 替换// 路由配置 title: 用户详情 - ${id}访问 /user/1 时渲染为 用户详情 - 1getPageTitle(pageTitle, route)默认导出在此基础上拼接config.appName定义于 web/src/core/config.js值为Gin-Vue-Admin作为浏览器标签页标题的统一生成入口。六、跨组件通信bus.js与closeThisPage.js6.1bus.js事件总线文件位置web/src/utils/bus.jsimport mitt from mitt export const emitter mitt()基于轻量事件库mitt的全局 emitter是文档“跨组件通信优先使用事件总线避免滥用 Pinia”的落地载体。例如request.js的全局错误提示正是通过emitter.emit(show-error, {...})广播给全局错误组件对应 web/src/components/errorPreview 相关实现的。典型用法import { emitter } from /utils/bus // 订阅注意在 onUnmounted 中取消避免泄漏 emitter.on(refresh-table, refreshList) // 发布 emitter.emit(refresh-table)6.2closeThisPage.js关闭当前标签页文件位置web/src/utils/closeThisPage.jsimport { emitter } from /utils/bus.js export const closeThisPage () { emitter.emit(closeThisPage) }通过事件总线广播closeThisPage事件由布局层的标签页管理组件见 web/src/view/layout监听并执行关闭逻辑从而将“关闭行为”从具体页面解耦。七、图片与文件域image.js、downloadImg.js7.1image.js图片压缩与 URL 处理文件位置web/src/utils/image.jsImageCompress类负责图片前端压缩核心流程FileReader读取为 DataURL →canvas等比缩放绘制 →toDataURL(type, 0.9)输出 → 转 Blob 再包装为Fileimport ImageCompress from /utils/image const compressor new ImageCompress(file, fileSize, 1920) const newFile await compressor.compress()关键参数参数默认值含义file—原始文件fileSize—目标体积KB压缩后超限时仅 console 告警maxWH1920最大长宽长边超限时按比例缩小dWH方法实现同文件导出的getUrl(url)根据VITE_FILE_API拼接文件访问地址已带http前缀或路径为/时原样返回配套ReturnArrImg、onDownloadFile使用另有isVideoExt/isVideoMime/isImageMime用于文件类型判定配合 media 文件上传下载 模块的场景区分。7.2downloadImg.js图片下载文件位置web/src/utils/downloadImg.jsdownloadImage(imgsrc, name)解决跨域图片下载问题通过设置crossOrigin anonymous加载图片绘制到 canvas 后toDataURL(image/png)生成 base64再触发a download点击实现下载避免直接window.open跨域被浏览器拦截。八、环境、文档与 DOM 事件8.1env.js环境判断文件位置web/src/utils/env.jsexport const isDev import.meta.env.DEV export const isProd import.meta.env.PROD基于 Vite 内置环境标志用于在代码中区分开发/生产行为如仅开发环境输出调试信息。8.2doc.js文档跳转文件位置web/src/utils/doc.jsexport const toDoc (url) { window.open(url, _blank) }统一的新窗口打开入口便于集中管理文档外链的打开策略。8.3event.jsDOM 事件管理文件位置web/src/utils/event.jsaddEventListen(target, event, handler, capture)与removeEventListen(target, event, handler, capture)对原生addEventListener/removeEventListener做了能力检测封装避免在不支持的环境中直接调用报错常用于弹窗组件或页面级滚动监听。九、强制使用场景速查文档末尾给出了 6 条不可绕过的强制约束结合源码整理为可直接对照的检查清单场景必须使用源码依据发起 HTTP 请求/utils/requestweb/src/utils/request.js获取字典数据/utils/dictionaryweb/src/utils/dictionary.js生成 UUIDCreateUUIDweb/src/utils/format.js处理按钮权限useBtnAuthweb/src/utils/btnAuth.js命名格式转换/utils/stringFunweb/src/utils/stringFun.js跨组件通信事件总线mittweb/src/utils/bus.js示例组合一个典型的“获取字典 → 发请求 → 格式化展示”链路import request from /utils/request import { getDict } from /utils/dictionary import { filterDict, formatDate, CreateUUID } from /utils/format async function loadUsers() { const statusDict await getDict(user_status) // 字典 const list await request({ url: /user/list, method: get }) return list.map((row) ({ ...row, statusLabel: filterDict(row.status, statusDict), // 值转标签 createAt: formatDate(row.createAt), // 时间格式化 key: CreateUUID() // 前端临时 key })) }十、总结GVA 的web/src/utils/并非零散函数的堆砌而是一套围绕“请求、格式化、字典、路由权限、通信、媒体”六大域组织的前端基础设施request.js统一了认证、loading、错误处理与 token 刷新是全站数据访问的事实标准dictionary.js / params.js通过 Pinia 缓存避免重复请求并支持树形字典的深度裁剪asyncRouter.js / btnAuth.js支撑了后端驱动的前端路由与按钮权限体系bus.js以事件总线承接全局错误提示与标签页关闭等跨组件协作避免状态被过度塞进 store。对于二次开发而言最实用的习惯是新增功能前先检索web/src/utils/目录建议结合 frontend-utils.md 与 前端规则 一并阅读优先复用既有工具确需扩展时也尽量在对应工具文件中增量补充保持这一层能力的收敛与可维护性。【免费下载链接】gin-vue-adminViteVue3Gin拥有AI辅助的基础开发平台企业级业务AI开发解决方案内置mcp辅助服务内置skills管理支持TS和JS混用。它集成了JWT鉴权、权限管理、动态路由、显隐可控组件、分页封装、多点登录拦截、资源权限、上传下载、代码生成器、表单生成器和可配置的导入导出等开发必备功能。项目地址: https://gitcode.com/gh_mirrors/gi/gin-vue-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表