Files
guilixu-admin/src/utils/image.ts
T
gxwebsoft 3bc856fc95 feat(shopGoods): 优化商品列表加载及封面图性能
- image.ts 中 getCompressedImageUrl 增加缓存,避免列表重渲染时重复计算压缩 URL
- shopGoods 页面用原生 img 标签替换 antdv a-image,支持浏览器懒加载减少首屏网络压力
- shopGoods 页面数据加载流程优化,取消表格自动首屏加载,改为手动触发,合并请求避免重复调用
- 首屏分类数据延迟加载,不阻塞首屏渲染,提升页面响应速度
- search.vue 中用 onMounted 替代 watch immediate,防止首次入场重复触发请求
- 新增商品封面图样式,保证图片大小固定且样式统一
2026-08-06 17:19:15 +08:00

119 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 图片压缩参数配置
*/
export interface ImageCompressOptions {
/** 图片宽度(px),默认 300 */
width?: number;
/** 图片质量 0-100,默认 90 */
quality?: number;
/** 是否启用压缩,默认 true */
enabled?: boolean;
}
/**
* 默认压缩参数
*/
const DEFAULT_OPTIONS: Required<ImageCompressOptions> = {
width: 240,
quality: 90,
enabled: true
};
/**
* OSS 域名(文件上传接口同域)
*/
const OSS_BASE_URL = 'https://oss.wsdns.cn';
/**
* 确保图片 URL 为完整路径
*
* 后端可能返回相对路径(如 /uploads/xxx.jpg),需要补全 OSS 域名。
*
* @param url 原始图片 URL
* @returns 完整图片 URL
*/
export function ensureFullUrl(url: string): string {
if (!url) return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
// 相对路径:补全 OSS 域名
return `${OSS_BASE_URL}${url.startsWith('/') ? '' : '/'}${url}`;
}
/**
* 移除 URL 中已有的 x-oss-process 参数(无论其在 query 中的位置)
*
* 阿里云 OSS 的图片处理参数通常以 `x-oss-process=image/...` 形式附加在 query 中,
* 可能位于首个或后续参数位。本函数精确剔除该参数,保留其余 query 参数。
*
* @param url 完整图片 URL
* @returns 已剥离 x-oss-process 的 URL
*/
function removeOssProcess(url: string): string {
const qIndex = url.indexOf('?');
if (qIndex === -1) return url;
const base = url.slice(0, qIndex);
const params = url
.slice(qIndex + 1)
.split('&')
.filter((p) => !p.startsWith('x-oss-process='));
return params.length ? `${base}?${params.join('&')}` : base;
}
/**
* 获取 OSS 压缩后的图片 URL
*
* 默认给图片 URL 拼接阿里云 OSS 图片处理参数,实现等比缩放 + 质量压缩。
* 使用场景:商品列表、商品卡片等缩略图展示。
*
* 注意:预览原图时不需要调用此函数,直接用原始 URL 即可。
*
* 优先级:以调用方指定的 width/quality 为准。若 URL 已自带 x-oss-process
* (接口已返回压缩参数),会先剥离再按本函数参数重新拼接,确保调用方参数生效。
*
* @param url 原始图片 URL
* @param options 压缩选项(width/quality 不传则使用默认值)
* @returns 处理后的图片 URL
*/
// 缓存已计算的压缩 URL,避免列表重渲染时(勾选、hover、滚动)重复拼接字符串
const compressedUrlCache = new Map<string, string>();
export function getCompressedImageUrl(
url: string,
options?: ImageCompressOptions
): string {
if (!url) return '';
// 命中缓存直接返回,省去重复计算
const cacheKey = options ? `${url}|${JSON.stringify(options)}` : url;
const cached = compressedUrlCache.get(cacheKey);
if (cached !== undefined) return cached;
// 先补全为完整 URL
const fullUrl = ensureFullUrl(url);
if (!fullUrl) {
compressedUrlCache.set(cacheKey, '');
return '';
}
const { width, quality, enabled } = { ...DEFAULT_OPTIONS, ...options };
// 未启用压缩,原样返回
if (!enabled) {
compressedUrlCache.set(cacheKey, fullUrl);
return fullUrl;
}
// 优先使用调用方指定的 width/quality
// 先剥离 URL 自带的 x-oss-process,再按本函数参数重新拼接,确保以调用方为准。
const baseUrl = removeOssProcess(fullUrl);
// 已有其他 query 参数用 & 拼接,否则用 ?
const separator = baseUrl.includes('?') ? '&' : '?';
const result = `${baseUrl}${separator}x-oss-process=image/resize,w_${width}/quality,Q_${quality}`;
compressedUrlCache.set(cacheKey, result);
return result;
}