/** * 图片压缩参数配置 */ export interface ImageCompressOptions { /** 图片宽度(px),默认 300 */ width?: number; /** 图片质量 0-100,默认 90 */ quality?: number; /** 是否启用压缩,默认 true */ enabled?: boolean; } /** * 默认压缩参数 */ const DEFAULT_OPTIONS: Required = { 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(); 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; }