Files
vtj/docs/llms/utils.md
“chenhuachun” bb1ed9f38f docs(api): 更新 originResponse 默认行为及取值说明
- 明确 originResponse 默认值为 true,返回完整 Axios 响应对象
- originResponse 为 false 时自动提取并返回业务数据 res.data?.data
- 更新错误示例,避免混淆完整响应对象与业务数据
- 统一文档中所有接口数据的访问方式,使用 res.data?.data 取业务数据
- 补充注意事项,提醒根据 originResponse 设置调整取值路径
- 相关示例代码更正为正确的数据访问方式
2026-06-21 15:05:54 +08:00

24 KiB
Raw Permalink Blame History

VTJ 工具库(@vtj/utils— AI 使用指南

本文档帮助 AI 理解如何使用 @vtj/utils 工具库中的各类工具方法在组件中实现网络请求、数据存储、URL 处理、文件下载等常见功能。


一、工具库概览

@vtj/utils 是 VTJ 平台的通用工具库,提供以下核心功能模块:

模块 功能 导入方式
request HTTP 请求封装(基于 axios import { request, createApi, createApis, useApi } from '@vtj/utils'
storage 本地存储localStorage/sessionStorage/内存缓存) import { storage } from '@vtj/utils'
cookie Cookie 操作 import { cookie } from '@vtj/utils'
url URL 解析与拼接 import { url } from '@vtj/utils'
download 文件下载 import { downloadUrl, downloadBlob, downloadJson } from '@vtj/utils'
logger 日志打印 import { logger } from '@vtj/utils'
loadScript 动态加载外部脚本 import { loadScript } from '@vtj/utils'
jsonp JSONP 跨域请求 import { jsonp } from '@vtj/utils'
client 客户端环境检测 import { getClientInfo } from '@vtj/utils'
raf requestAnimationFrame 封装 import { rAF, cAF } from '@vtj/utils'
util 通用工具函数 import { isClient, fileToBase64, formDataToJson } from '@vtj/utils'

二、HTTP 请求模块request

2.1 核心 API

方法 说明 返回值
request(config) 发送 HTTP 请求 Promise<R>
createApi(url | config, req?) 创建单个 API 函数 (data?, opts?) => Promise<R>
createApis(map, req?) 批量创建 API 函数 Record<string, Function>
useApi(loader, transform?) Composition API 风格的请求钩子 { data, error, loading, reload }

2.2 request 实例方法

request.send(config)        // 发送请求
request.cancel(id?)         // 取消请求(不传 id 取消全部)
request.setConfig(options)  // 修改全局配置
request.useRequest(fn)      // 请求拦截器
request.useResponse(fn)     // 响应拦截器

2.3 请求配置IRequestConfig

{
  url: string,              // 请求地址
  method: string,           // 请求方法get/post/put/patch/delete
  settings: {
    type: 'form' | 'json' | 'data',  // 数据格式(默认 form
    loading: boolean,                // 是否显示 loading
    showLoading: () => void,         // 自定义显示 loading
    hideLoading: () => void,         // 自定义隐藏 loading
    failMessage: boolean,            // 是否显示失败提示
    showError: (msg, e) => void,     // 自定义错误提示
    originResponse: boolean,         // 返回原始 axios 响应
    headers: object | function,      // 自定义请求头
    injectHeaders: boolean,          // 是否注入自定义请求头
    proxy: boolean,                  // 是否开启代理
    proxyPath: string                // 代理服务路径
  },
  query: object             // URL path 参数对象(用于路径参数替换)
}

2.4 使用示例

方式一:直接使用 request

import { request } from '@vtj/utils';

// GET 请求
const res = await request({
  url: '/api/users',
  method: 'get',
  settings: {
    type: 'json',
    loading: true
  }
});

// POST 请求form 格式)
const res = await request({
  url: '/api/users',
  method: 'post',
  data: { name: '张三', age: 25 }
});

// POST 请求JSON 格式)
const res = await request({
  url: '/api/users',
  method: 'post',
  settings: { type: 'json' },
  data: { name: '张三', age: 25 }
});

// 带路径参数query 用于替换 URL 中的 :id
const res = await request({
  url: '/api/users/:id',
  method: 'get',
  query: { id: 123 }
});
// 实际请求:/api/users/123

方式二:使用 createApi推荐

import { createApi } from '@vtj/utils';

// 创建 API 函数
const getUserList = createApi('/api/users');
const getUserById = createApi('/api/users/:id');
const createUser = createApi({
  url: '/api/users',
  method: 'post',
  settings: { type: 'json' }
});

// 调用 API
const list = await getUserList();
const user = await getUserById(null, { query: { id: 123 } });
const newUser = await createUser({ name: '张三' });

方式三:使用 createApis 批量创建

import { createApis } from '@vtj/utils';

const __apis = createApis({
  getUserList: '/api/users',
  getUserById: '/api/users/:id',
  createUser: {
    url: '/api/users',
    method: 'post',
    settings: { type: 'json' }
  },
  updateUser: {
    url: '/api/users/:id',
    method: 'put',
    settings: { type: 'json' }
  },
  deleteUser: {
    url: '/api/users/:id',
    method: 'delete'
  }
});

// 在组件中使用
onMounted(async () => {
  const res = await __apis.getUserList();
  __state.userList = res.data?.data || [];
});

// 带路径参数调用
await __apis.getUserById(null, { query: { id: 123 } });

// 带请求体调用
await __apis.createUser({ name: '张三', age: 25 });

方式四:使用 useApi 钩子

import { useApi, createApi } from '@vtj/utils';

const getUserList = createApi('/api/users');

// 自动加载数据
const { data, error, loading, reload } = useApi(getUserList());

// 带数据转换
const { data } = useApi(getUserList(), (res) => res.data?.data?.list || []);

2.5 params 与 query 的职责区分

⚠️ 重要规范: 在 VTJ 的请求体系中,paramsquery 有明确的语义区分:

参数类型 用途 位置 示例
params URL 路径参数Path Parameters URL 路径中 /api/users/:id/api/users/123
query URL 查询参数Query Parameters URL ? 后面 /api/users?page=1&size=10

正确使用方式:

// ✅ params 用于路径参数替换
await request({
  url: '/api/users/:id',
  params: { id: 123 }
});
// 实际请求GET /api/users/123

// ✅ data 中的字段会自动成为查询参数GET 请求)
await request({
  url: '/api/users',
  method: 'get',
  data: { page: 1, size: 10 }
});
// 实际请求GET /api/users?page=1&size=10

// ✅ POST 请求中 params 用于路径参数data 用于请求体
await request({
  url: '/api/users/:id',
  method: 'post',
  params: { id: 123 },
  data: { name: '张三' }
});
// 实际请求POST /api/users/123
// 请求体:{ name: '张三' }

2.6 路径参数传参规范

当 API 地址包含路径参数(如 :id)时,必须通过 params 字段传入:

// API 定义
const __apis = createApis({
  getUser: '/api/users/:id',
  updateUser: {
    url: '/api/users/:id',
    method: 'put',
    settings: { type: 'json' }
  }
});

// 正确调用方式
await __apis.getUser(null, { params: { id: 123 } });
await __apis.updateUser({ name: '张三' }, { params: { id: 123 } });

原理说明: request 内部使用 pathToRegexpCompile 将 URL 中的 :paramName 替换为 params 对象中对应的值。


三、本地存储模块storage

3.1 核心 API

import { storage } from '@vtj/utils';

storage.save(key, value, opts?)   // 保存数据
storage.get(key, opts?)           // 读取数据
storage.remove(key, opts?)        // 删除数据
storage.clear(opts?)              // 清空存储
storage.config(opts?)             // 修改默认配置

3.2 存储类型type

类型 说明 过期支持 环境
local localStorage 支持 浏览器
session sessionStorage 支持 浏览器
cache 内存缓存 支持 所有环境

3.3 配置选项

{
  type: 'cache' | 'local' | 'session',  // 存储类型(默认 cache
  expired: number,                       // 过期时间毫秒0 为永不过期
  prefix: string                         // key 前缀(默认 '__VTJ_'
}

3.4 使用示例

import { storage } from '@vtj/utils';

// 保存数据(永不过期)
storage.save('userToken', 'abc123');

// 保存数据1 小时后过期)
storage.save('userToken', 'abc123', {
  type: 'local',
  expired: 60 * 60 * 1000
});

// 读取数据
const token = storage.get('userToken');

// 读取数据(指定存储类型)
const token = storage.get('userToken', { type: 'local' });

// 删除数据
storage.remove('userToken');

// 清空所有缓存
storage.clear();

// 修改默认配置
storage.config({
  type: 'local',
  prefix: 'MY_APP_'
});

3.5 在 Composition API 中使用

import { reactive, onMounted } from 'vue';
import { storage } from '@vtj/utils';

const __state = reactive({
  user: null,
  token: ''
});

onMounted(() => {
  // 从本地存储读取用户信息
  __state.token = storage.get('userToken') || '';
  __state.user = storage.get('userInfo', { type: 'local' });
});

function login(user) {
  __state.user = user;
  __state.token = user.token;

  // 保存到本地存储
  storage.save('userToken', user.token, {
    type: 'local',
    expired: 7 * 24 * 60 * 60 * 1000 // 7 天
  });
  storage.save('userInfo', user, {
    type: 'local',
    expired: 7 * 24 * 60 * 60 * 1000
  });
}

function logout() {
  storage.remove('userToken', { type: 'local' });
  storage.remove('userInfo', { type: 'local' });
  __state.user = null;
  __state.token = '';
}

四、Cookie 操作模块cookie

4.1 核心 API

import { cookie } from '@vtj/utils';

cookie.set(name, value, opts?)    // 设置 Cookie
cookie.get(name)                  // 读取 Cookie
cookie.remove(name, opts?)        // 删除 Cookie

4.2 配置选项

{
  expires: number,      // 过期天数
  path: string,         // 路径(默认 '/'
  domain: string,       // 域名
  secure: boolean,      // 仅 HTTPS
  sameSite: string      // SameSite 策略
}

4.3 使用示例

import { cookie } from '@vtj/utils';

// 设置 Cookie会话级别
cookie.set('userId', '12345');

// 设置 Cookie7 天过期)
cookie.set('userId', '12345', { expires: 7 });

// 设置 Cookie指定路径和域名
cookie.set('userId', '12345', {
  expires: 7,
  path: '/',
  domain: '.example.com'
});

// 读取 Cookie
const userId = cookie.get('userId');

// 删除 Cookie
cookie.remove('userId');

五、URL 处理模块url

5.1 核心 API

import { url } from '@vtj/utils';

url.stringify(query)              // 对象转查询字符串
url.parse(str?)                   // 查询字符串转对象
url.append(url, query)            // 在 URL 后追加参数
url.getHost(url)                  // 获取 URL 的 host
url.getCurrentHost(includePath)   // 获取当前页面 host

5.2 使用示例

import { url } from '@vtj/utils';

// 对象转查询字符串
const str = url.stringify({ page: 1, size: 10 });
// 结果:'page=1&size=10'

// 查询字符串转对象
const obj = url.parse('page=1&size=10');
// 结果:{ page: '1', size: '10' }

// 获取当前 URL 参数
const params = url.parse();
// 结果:从 location.search 解析参数

// 在 URL 后追加参数
const newUrl = url.append('/api/users', { page: 2 });
// 结果:'/api/users?page=2'

// 追加参数到已有参数的 URL
const newUrl = url.append('/api/users?sort=asc', { page: 2 });
// 结果:'/api/users?sort=asc&page=2'

// 获取 URL 的 host
const host = url.getHost('https://example.com/api/users');
// 结果:'https://example.com'

// 获取当前页面 host
const host = url.getCurrentHost(false);
// 结果:'https://example.com'

const hostWithPath = url.getCurrentHost(true);
// 结果:'https://example.com/path/to/page'

六、文件下载模块download

6.1 核心 API

import { downloadUrl, downloadBlob, downloadJson, downloadRemoteFile } from '@vtj/utils';

downloadUrl(url, filename?)              // 下载指定 URL 的文件
downloadBlob(data, filename?, type?)     // 下载 Blob 数据
downloadJson(data, filename?)            // 下载 JSON 数据
downloadRemoteFile(url, filename?, type?)// 下载远程文件

6.2 使用示例

import {
  downloadUrl,
  downloadBlob,
  downloadJson,
  downloadRemoteFile
} from '@vtj/utils';

// 下载 URL 文件
downloadUrl('https://example.com/file.pdf', 'report.pdf');

// 下载 JSON 数据
const data = { name: '张三', age: 25 };
downloadJson(data, 'user.json');

// 下载 Blob 数据CSV 文件)
const csvContent = 'name,age\n张三,25';
downloadBlob(csvContent, 'users.csv', 'text/csv');

// 下载远程文件
await downloadRemoteFile(
  'https://example.com/image.png',
  'avatar.png',
  'image/png'
);

6.3 在组件中使用

import { reactive } from 'vue';
import { downloadJson, createApi } from '@vtj/utils';

const exportData = createApi('/api/users/export');

const __state = reactive({
  async exportUsers() {
    const res = await exportData();
    downloadJson(res.data?.data, 'users.json');
  }
});

七、日志模块logger

7.1 核心 API

import { logger, getLogger } from '@vtj/utils';

logger.debug(...args); // 调试日志
logger.log(...args); // 普通日志
logger.info(...args); // 信息日志
logger.warn(...args); // 警告日志
logger.error(...args); // 错误日志

7.2 日志级别

级别 说明
debug -1 调试信息
log/info 0 普通信息
warn 1 警告信息
error 2 错误信息

7.3 使用示例

import { logger, getLogger } from '@vtj/utils';

// 使用默认 loggerbizName: 'VTJ'
logger.info('页面加载完成');
logger.warn('用户未登录');
logger.error('请求失败', error);

// 创建自定义 logger
const myLogger = getLogger({
  level: 'debug',
  bizName: 'MyApp'
});

myLogger.debug('调试信息');
myLogger.info('[MyApp] 业务日志');

// 日志输出格式:[bizName] message
// 例如:[VTJ] 页面加载完成

7.4 动态控制日志级别

通过 URL 参数控制日志输出:

https://example.com?__logConf__=debug
https://example.com?__logConf__=warn:MyApp

格式:__logConf__=logLevel[:bizName]


八、动态脚本加载loadScript

8.1 核心 API

import { loadScript } from '@vtj/utils';

loadScript(src, options?)  // 动态加载外部 JS 脚本

8.2 配置选项

{
  async: boolean,           // 是否异步加载(默认 true
  attrs: object,            // 自定义属性
  charset: string,          // 字符集(默认 'utf-8'
  text: string,             // 追加的脚本内容
  type: string,             // 脚本类型(默认 'text/javascript'
  library: string           // window 上的全局变量名
}

8.3 使用示例

import { loadScript } from '@vtj/utils';

// 加载外部脚本
await loadScript('https://cdn.example.com/chart.js');

// 加载并获取全局变量
const Chart = await loadScript('https://cdn.example.com/chart.js', {
  library: 'Chart'
});

// 加载带自定义属性
await loadScript('https://cdn.example.com/sdk.js', {
  async: true,
  attrs: {
    'data-app-id': '12345'
  }
});

九、JSONP 跨域请求jsonp

9.1 核心 API

import { jsonp } from '@vtj/utils';

jsonp(url, options?)  // 发送 JSONP 请求

9.2 配置选项

{
  query: object,                // 查询参数
  timeout: number,              // 超时时间(毫秒)
  jsonpCallback: string,        // 回调函数名
  jsonpCallbackFunction: string // 回调函数名
}

9.3 使用示例

import { jsonp } from '@vtj/utils';

// 基础 JSONP 请求
const data = await jsonp('https://api.example.com/data');

// 带查询参数
const data = await jsonp('https://api.example.com/data', {
  query: { page: 1, size: 10 }
});

// 带模板字符串的 URL
const data = await jsonp('https://api.example.com/users/${id}', {
  query: { id: 123 }
});

十、客户端环境检测client

10.1 核心 API

import { getClientInfo } from '@vtj/utils';

getClientInfo(); // 获取客户端环境信息

10.2 返回值

{
  os: string,              // 操作系统Windows/Mac OS/iOS/Android/Linux
  osVersion: string,       // 系统版本
  browser: string,         // 浏览器Chrome/Safari/Firefox/Edge/Opera/IE
  browserVersion: string,  // 浏览器版本
  isMobile: boolean        // 是否为移动设备
}

10.3 使用示例

import { getClientInfo } from '@vtj/utils';

const info = getClientInfo();

if (info.isMobile) {
  console.log('移动设备:', info.os, info.browser);
} else {
  console.log('桌面设备:', info.os, info.browser);
}

十一、requestAnimationFrame 封装raf

11.1 核心 API

import { rAF, cAF } from '@vtj/utils';

rAF(fn); // 请求动画帧(兼容 SSR
cAF(handle); // 取消动画帧

11.2 使用示例

import { rAF, cAF } from '@vtj/utils';

let handle;

function animate() {
  // 动画逻辑
  handle = rAF(animate);
}

// 开始动画
handle = rAF(animate);

// 停止动画
cAF(handle);

十二、通用工具函数util

12.1 核心 API

import {
  isClient,
  fileToBase64,
  formDataToJson,
  dataURLtoBlob,
  blobToFile
} from '@vtj/utils';

isClient; // 是否为浏览器环境
fileToBase64(file); // File 转 Base64
formDataToJson(data); // FormData 转 JSON
dataURLtoBlob(dataurl); // Base64 转 Blob
blobToFile(blob, fileName); // Blob 转 File

12.2 使用示例

import { isClient, fileToBase64, formDataToJson } from '@vtj/utils';

// 环境检测
if (isClient) {
  // 浏览器环境代码
  console.log(window.location.href);
}

// File 转 Base64
const base64 = await fileToBase64(file);

// FormData 转 JSON
const json = formDataToJson(formData);

十三、日期处理dayjs / dateFormat

13.1 核心 API

import { dayjs, dateFormat } from '@vtj/utils';

dayjs(date);                        // 创建 dayjs 实例(已内置 zh-cn  locale
dateFormat(date, format?);          // 格式化日期字符串

13.2 使用示例

import { dayjs, dateFormat } from '@vtj/utils';

// 使用 dateFormat 快速格式化
const now = dateFormat(new Date());
// 结果:'2024-06-15 14:30:00'(默认格式 YYYY-MM-DD HH:mm:ss

const dateStr = dateFormat('2024-03-15', 'YYYY-MM-DD');
// 结果:'2024-03-15'

const chineseDate = dateFormat(new Date(), 'YYYY年MM月DD日');
// 结果:'2024年06月15日'

// 直接使用 dayjs 实例进行链式操作
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');

const diffDays = dayjs('2024-06-15').diff('2024-01-01', 'day');

const startOfMonth = dayjs().startOf('month').format('YYYY-MM-DD');

// 解析时间戳
const fromTimestamp = dayjs(1718400000000).format('YYYY-MM-DD HH:mm:ss');

13.3 在组件中使用

import { reactive } from 'vue';
import { dateFormat, dayjs } from '@vtj/utils';

const __state = reactive({
  currentDate: dateFormat(new Date()),
  expireDate: dayjs().add(7, 'day').format('YYYY-MM-DD HH:mm:ss')
});

注意: @vtj/utils 导出的 dayjs 已默认设置 locale('zh-cn'),无需再次配置中文语言包。


十四、典型工作流程

14.1 数据获取与展示

import { reactive, onMounted } from 'vue';
import { createApis, storage } from '@vtj/utils';

const __apis = createApis({
  getUserList: '/api/users',
  getUserById: '/api/users/:id'
});

const __state = reactive({
  users: [],
  loading: false
});

onMounted(async () => {
  // 尝试从缓存读取
  const cached = storage.get('userList', { type: 'local' });
  if (cached) {
    __state.users = cached;
    return;
  }

  // 从服务器获取
  __state.loading = true;
  try {
    const res = await __apis.getUserList();
    __state.users = res.data?.data || [];

    // 缓存 5 分钟
    storage.save('userList', __state.users, {
      type: 'local',
      expired: 5 * 60 * 1000
    });
  } finally {
    __state.loading = false;
  }
});

14.2 文件上传与下载

import { reactive } from 'vue';
import { createApi, downloadBlob, fileToBase64 } from '@vtj/utils';

const uploadFile = createApi({
  url: '/api/upload',
  method: 'post',
  settings: { type: 'data' } // multipart/form-data
});

const __state = reactive({
  async handleUpload(file) {
    // File 转 Base64
    const base64 = await fileToBase64(file);

    // 上传文件
    const formData = new FormData();
    formData.append('file', file);
    const res = await uploadFile(formData);

    return res.data?.data;
  },

  async handleExport() {
    const res = await __apis.exportData();
    downloadBlob(res.data?.data, 'export.xlsx', 'application/vnd.ms-excel');
  }
});

14.3 动态加载第三方库

import { reactive, onMounted } from 'vue';
import { loadScript } from '@vtj/utils';

const __state = reactive({
  chartLoaded: false
});

onMounted(async () => {
  try {
    const Chart = await loadScript('https://cdn.example.com/chart.js', {
      library: 'Chart'
    });

    if (Chart) {
      __state.chartLoaded = true;
      // 使用 Chart 库
    }
  } catch (error) {
    logger.error('加载图表库失败', error);
  }
});

十五、注意事项

  1. request 默认 originResponse: true 默认返回完整的 axios 响应对象,设置 originResponse: false 才会自动提取并返回 res.data?.data
  2. query 与 params 语义区分: query 用于路径参数替换,请求体数据使用 data 字段
  3. storage 支持过期机制: 过期时间单位为毫秒0 表示永不过期
  4. isClient 用于 SSR 兼容: 在非浏览器环境中访问 window 前先判断 isClient
  5. logger 支持动态级别控制: 通过 URL 参数 __logConf__ 可以动态调整日志输出
  6. loadScript 返回 Promise 加载成功返回 window 上的全局变量(如果指定了 library
  7. download 方法需要浏览器环境: 依赖 document.createElementSSR 环境下不可用
  8. cookie 基于 js-cookie 完整 API 参考 js-cookie 文档

十六、从 @vtj/base 继承的工具

@vtj/utils 还从 @vtj/base 导出了以下常用工具:

import {
  merge, // 深度合并对象
  omit, // 排除对象属性
  debounce, // 防抖函数
  throttle, // 节流函数
  uuid, // 生成唯一 ID
  pathToRegexpCompile, // 路径参数编译
  isUrl, // 判断是否为 URL
  template // 模板字符串编译
} from '@vtj/utils';

这些工具在 request、storage、url 等模块内部广泛使用,也可以在业务代码中直接使用。