文章目录需求分析解决1. 行内缩略图预览2. 计算属性收集当前页所有图片 URL3. 「预览」按钮构建完整预览列表4. 主逻辑5. 关键点6. 图片查看器组件7. 关键设计决策需求实现图片预览上一张/下一张切换功能分析实现手动预览实现上一张/下一张切换代码实现templatedivclassflex gap-12divclassgrid gap-3el-button clickhandleClickopenPreview with showPreview method/el-buttonel-imagerefimageRefstylewidth: 100px; height: 100px:srcurlshow-progress :preview-src-listsrcListfitcover//divdivel-button clickshowPreview truepreview controlled/el-buttonel-image-viewer v-ifshowPreview:url-listsrcListshow-progress :initial-index4closeshowPreview false//div/div/templatescriptlangtssetupimport{ref}fromvueimporttype{ImageInstance}fromelement-plusconst urlhttps://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpegconst srcList[https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg,https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg,https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg,https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg,https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg,https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg,https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg,]const imageRefrefImageInstance()const showPreviewref(false)const handleClick(){imageRef.value!.showPreview()}/script解决由于我是在table中做这个功能所以需要对之前的代码做一个改动1. 行内缩略图预览修改前 — 每行只传自己的 URL无法切换el-image :srcscope.row.url || scope.row.goflyUrl:preview-src-list[scope.row.url || scope.row.goflyUrl]/修改后 — 传入当前页全部图片的 URL 列表Element Plus 自动匹配点击位置el-image v-ifscope.row.albumType 1:srcscope.row.url || scope.row.goflyUrl:preview-src-listrawImagePreviewListpreview-teleported /2. 计算属性收集当前页所有图片 URL使用 computed列表数据变化时自动更新/** 行内el-image预览使用的原始图片URL列表 */ const rawImagePreviewListcomputed((){ return list.value .filter(rr.albumType1(r.url||r.goflyUrl)).map(rr.url||r.goflyUrl)})3. 「预览」按钮构建完整预览列表关键函数/** 获取当前页同类型所有可预览项 */ const buildTypeList(type: number){returnlist.value.filter(rr.albumTypetype(r.url||r.goflyUrl))}/** 解析单个素材URL含infra/file的需调接口 */ const resolveUrlasync(item: any){const urlitem.url||item.goflyUrlif(url.includes(infra/file)){returnawait dataImages.getMaterialResourceUrl({url})}returnurl}4. 主逻辑const handlePreviewasync(row: any){const urlrow.url||row.goflyUrlif(!url){message.warning(暂无预览内容)return}const isImagerow.albumType1previewType.valueisImage ?image:videoif(isImage){// 图片构建当前页全部图片列表支持上下张切换 const itemsbuildTypeList(1)previewIndex.valueitems.findIndex(rr.idrow.id)previewList.valueawait Promise.all(items.map(rresolveUrl(r)))}else{// 视频仅预览当前单个视频 previewList.value[await resolveUrl(row)]}previewVisible.valuetrue}5. 关键点findIndex 找到当前行在同类型列表中的位置传给 initial-indexPromise.all 并行解析所有 URL含需要调用 getMaterialResourceUrl 接口的图片和视频分开处理图片构建完整列表视频保持单张6. 图片查看器组件el-image-viewer v-ifpreviewVisible previewType image :url-listpreviewList :initial-indexpreviewIndex closepreviewVisible false /url-list所有图片 URL组件据此生成切换列表initial-index指定从第几张开始显示el-image-viewer自带上一张/下一张箭头和键盘左右键切换7. 关键设计决策决策说明图片和视频分离处理图片用 Element Plus 内置查看器自带切换视频用自定义遮罩层因video不能用el-image展示仅切换同类型素材图片只切换图片视频不参与图片切换列表避免混排时类型不一致URL 解析并行化用Promise.all批量调用getMaterialResourceUrl避免逐个串行等待不缓存解析结果每次点击预览重新解析确保 URL 不过期页数小10条/页无性能问题