Element UI el-image 正式环境中预览图片时,始终从第一张图片开始显示
...大约 3 分钟
Element UI el-image 正式环境中预览图片时,始终从第一张图片开始显示
背景
迭代一个老项目,发现个bug,在开发环境中,el-image 的预览功能正常工作:点击哪张图片,预览就从哪张开始。但部署到正式环境后,无论点击哪张图片,预览总是从第一张开始显示。这篇文章记录了问题的排查过程和解决方案。
一、问题现象
1、开发环境(正常)
- 点击第 2 张图片 → 预览显示第 2 张
- 点击第 3 张图片 → 预览显示第 3 张
2、正式环境(异常)
- 点击第 2 张图片 → 预览显示第 1 张 ❌
- 点击第 3 张图片 → 预览显示第 1 张 ❌
二、问题代码
<template>
<div class="dialog-img">
<div>
<el-image :src="formData.businessLicense" :preview-src-list="previewList"></el-image>
<p>营业执照</p>
</div>
<div>
<el-image :src="formData.frontOfCorporateIdCard" :preview-src-list="previewList"></el-image>
<p>法人身份证正面</p>
</div>
<div>
<el-image :src="formData.backOfCorporateIdCard" :preview-src-list="previewList"></el-image>
<p>法人身份证反面</p>
</div>
<div>
<el-image :src="formData.certificateOfAuthorization" :preview-src-list="previewList"></el-image>
<p>法人授权书</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
previewList: [],
formData: {
businessLicense: '',
frontOfCorporateIdCard: '',
backOfCorporateIdCard: '',
certificateOfAuthorization: ''
}
}
},
methods: {
getAllPreview() {
this.previewList = []
this.formData.businessLicense && this.previewList.push(this.formData.businessLicense)
this.formData.frontOfCorporateIdCard && this.previewList.push(this.formData.frontOfCorporateIdCard)
this.formData.backOfCorporateIdCard && this.previewList.push(this.formData.backOfCorporateIdCard)
this.formData.certificateOfAuthorization && this.previewList.push(this.formData.certificateOfAuthorization)
}
}
}
</script>三、问题原因分析
1、el-image 预览原理
el-image 组件在预览时,内部会维护一个当前显示图片的索引(initial-index,默认值为 0)。当多个 el-image 共享同一个 preview-src-list 时:
- 点击某张图片触发预览
- 组件尝试找到当前图片在
preview-src-list中的索引位置 - 从该索引位置开始显示预览
2、为什么开发环境和正式环境表现不同?
| 环境 | 代码状态 | Vue 渲染行为 | 结果 |
|---|---|---|---|
| Dev | 未压缩 | 组件按预期顺序初始化,内部状态稳定 | 正常 |
| Prod | 压缩优化 | 代码压缩后,Vue 的 diff 算法和组件复用机制可能导致 el-image 内部索引计算出现偏差 | 异常 |
根本原因:正式环境代码经过 Webpack 压缩和 Vue 运行时优化后,el-image 组件内部的索引匹配逻辑受到影响,无法正确识别当前点击的图片在 preview-src-list 中的位置,于是回退到默认的 initial-index: 0(第一张图)。
四、解决方案
方案一:使用 initial-index 手动控制(推荐)
通过 initial-index 属性手动指定预览起始位置,配合点击事件动态设置:
<template>
<div class="dialog-img">
<div v-show="formData.businessLicense">
<el-image
:src="formData.businessLicense"
:initial-index="initialIndex"
:preview-src-list="previewList"
@click="handleImageClick(0)"></el-image>
<p>营业执照</p>
</div>
<div>
<el-image
:src="formData.frontOfCorporateIdCard"
:initial-index="initialIndex"
@click="handleImageClick(1)"
:preview-src-list="previewList"></el-image>
<p>法人身份证正面</p>
</div>
<div>
<el-image
:src="formData.backOfCorporateIdCard"
:initial-index="initialIndex"
@click="handleImageClick(2)"
:preview-src-list="previewList"></el-image>
<p>法人身份证反面</p>
</div>
<div>
<el-image
:src="formData.certificateOfAuthorization"
:preview-src-list="previewList"
:initial-index="initialIndex"
@click="handleImageClick(3)"></el-image>
<p>法人授权书</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
initialIndex: 0,
previewList: [],
formData: {
businessLicense: '',
frontOfCorporateIdCard: '',
backOfCorporateIdCard: '',
certificateOfAuthorization: ''
}
}
},
methods: {
handleImageClick(index) {
this.initialIndex = index
},
getAllPreview() {
this.previewList = []
this.formData.businessLicense && this.previewList.push(this.formData.businessLicense)
this.formData.frontOfCorporateIdCard && this.previewList.push(this.formData.frontOfCorporateIdCard)
this.formData.backOfCorporateIdCard && this.previewList.push(this.formData.backOfCorporateIdCard)
this.formData.certificateOfAuthorization && this.previewList.push(this.formData.certificateOfAuthorization)
}
}
}
</script>优点:
- 保持原有的预览列表功能(可以左右切换查看所有图片)
- 明确控制预览起始位置,不受环境差异影响
方案二:独立 preview-src-list(简单场景适用)
如果不需要左右切换查看所有图片,每个图片只预览自己:
<template>
<div class="dialog-img">
<div>
<el-image :src="formData.businessLicense" :preview-src-list="[formData.businessLicense]"></el-image>
<p>营业执照</p>
</div>
<div>
<el-image :src="formData.frontOfCorporateIdCard" :preview-src-list="[formData.frontOfCorporateIdCard]"></el-image>
<p>法人身份证正面</p>
</div>
<!-- 其他图片同理 -->
</div>
</template>缺点:无法左右切换查看其他图片
五、总结
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| initial-index | 需要左右切换预览 | 功能完整,环境兼容性好 | 需要额外代码 |
| 独立 preview-src-list | 单张预览即可 | 代码简单 | 无法切换预览 |
建议
对于需要完整预览功能的场景,使用 方案一 的 initial-index 方式,显式控制预览起始位置,避免环境差异导致的问题。