3bc856fc95
- image.ts 中 getCompressedImageUrl 增加缓存,避免列表重渲染时重复计算压缩 URL - shopGoods 页面用原生 img 标签替换 antdv a-image,支持浏览器懒加载减少首屏网络压力 - shopGoods 页面数据加载流程优化,取消表格自动首屏加载,改为手动触发,合并请求避免重复调用 - 首屏分类数据延迟加载,不阻塞首屏渲染,提升页面响应速度 - search.vue 中用 onMounted 替代 watch immediate,防止首次入场重复触发请求 - 新增商品封面图样式,保证图片大小固定且样式统一
119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
/**
|
||
* 图片压缩参数配置
|
||
*/
|
||
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;
|
||
}
|