perf(image): 优化图片加载性能

- 为所有商品图片添加 loading="lazy" 属性实现懒加载
- 为所有图片元素添加 decoding="async" 属性实现异步解码
- 优化购物车页面的商品缩略图加载方式
- 改进订单中心各页面的图片加载策略
- 提升评价系统中图片的加载性能
- 优化会员中心收藏和足迹功能的图片加载
- 改善促销活动页面的图片加载体验
- 更新首页装饰组件中的图片加载属性
- 提高地址管理页面的界面展示效果
This commit is contained in:
pikachu1995@126.com
2026-10-08 14:36:22 +08:00
parent 4c232284f8
commit 1b275cf592
34 changed files with 333 additions and 92 deletions

View File

@@ -111,6 +111,8 @@
goods.goodsSku.thumbnail ||
'../assets/images/goodsDetail/item-detail-1.jpg'
"
loading="lazy"
decoding="async"
/>
<div>
<p>

View File

@@ -81,7 +81,7 @@
@click="goGoodsDetail(item.id, item.goodsId)"
>
<div class="goods-show-img">
<img :src="item.thumbnail || item.small" alt=""/>
<img :src="item.thumbnail || item.small" loading="lazy" decoding="async" alt=""/>
</div>
<div class="goods-show-price">
<span class="seckill-price text-danger">{{ $filters.unitPrice(item.price, "¥") }}</span>

View File

@@ -13,7 +13,7 @@
</div>
<div class="add-info-box-row">
<div class="add-info-img">
<img :src="detail.thumbnail" alt="">
<img :src="detail.thumbnail" loading="lazy" decoding="async" alt="">
</div>
<div class="add-info-intro">
<p>{{detail.goodsName}}</p>

View File

@@ -21,6 +21,8 @@
<div class="goods-thumb" @click="linkTo(`/goodsDetail?goodsId=${item.goodsId}&skuId=${item.skuId}`)">
<img
:src="item.goodsImage"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>

View File

@@ -14,7 +14,7 @@
<tbody>
<tr>
<td>投诉商品</td>
<td class="hover-color" @click="linkTo(`/goodsDetail?goodsId=${detail.goodsId}&skuId=${detail.skuId}`)"><img :src="detail.goodsImage" width="60" alt=""> &nbsp;{{ detail.goodsName }}</td>
<td class="hover-color" @click="linkTo(`/goodsDetail?goodsId=${detail.goodsId}&skuId=${detail.skuId}`)"><img :src="detail.goodsImage" loading="lazy" decoding="async" width="60" alt=""> &nbsp;{{ detail.goodsName }}</td>
</tr>
<tr>
<td>投诉主题</td>
@@ -30,7 +30,7 @@
<div style="display:flex;align-items:center;">
<template v-if="detail.images">
<div class="demo-upload-list" v-for="(img, index) in detail.images.split(',')" :key="index">
<img :src="img">
<img :src="img" loading="lazy" decoding="async">
<div class="demo-upload-list-cover">
<el-icon @click="handleView(img)"><View /></el-icon>
</div>
@@ -61,7 +61,7 @@
<div style="display:flex;align-items:center;">
<template v-if="detail.appealImages">
<div class="demo-upload-list" v-for="(img, index) in detail.appealImages.split(',')" :key="index">
<img :src="img">
<img :src="img" loading="lazy" decoding="async">
<div class="demo-upload-list-cover">
<el-icon @click="handleView(img)"><View /></el-icon>
</div>
@@ -124,7 +124,7 @@
</table>
<el-dialog title="图片预览" v-model="visible">
<img :src="previewImage" v-if="visible" style="width: 100%">
<img :src="previewImage" loading="lazy" decoding="async" v-if="visible" style="width: 100%">
</el-dialog>
</UserCenterLayout>
</div>

View File

@@ -22,6 +22,8 @@
<div class="goods-thumb" @click="linkTo(`/goodsDetail?goodsId=${item.goodsId}&skuId=${item.skuId}`)">
<img
:src="item.goodsImage"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>
@@ -286,3 +288,7 @@ export default {

View File

@@ -18,6 +18,8 @@
<div class="fav-thumb" @click="openItem(item)">
<img
:src="params.type === 'GOODS' ? item.image : item.storeLogo"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>
@@ -55,6 +57,8 @@
<div class="fav-thumb" @click="openItem(item)">
<img
:src="params.type === 'GOODS' ? item.image : item.storeLogo"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>

View File

@@ -20,7 +20,7 @@
<ul class="goods-eval">
<li >
<div class="goods-con">
<img :src="orderGoods.image" class="hover-pointer" alt="" width="100" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">
<img :src="orderGoods.image" loading="lazy" decoding="async" class="hover-pointer" alt="" width="100" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">
<p class="hover-pointer color999" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">{{orderGoods.goodsName}}</p>
<p>{{ $filters.unitPrice(orderGoods.goodsPrice, '¥') }}</p>
</div>
@@ -40,7 +40,7 @@
<div class="upload-section">
<div class="upload-row">
<div class="demo-upload-list" v-for="(img, index) in orderGoods.uploadList" :key="index">
<img :src="img">
<img :src="img" loading="lazy" decoding="async">
<div class="demo-upload-list-cover">
<el-icon @click="handleView(img)"><View /></el-icon>
<el-icon @click="handleRemove(index)"><Delete /></el-icon>
@@ -69,7 +69,7 @@
<el-button type="primary" :loading="loading" @click="save">发表</el-button>
</div>
<el-dialog title="图片预览" v-model="visible">
<img :src="previewImage" v-if="visible" style="width: 100%">
<img :src="previewImage" loading="lazy" decoding="async" v-if="visible" style="width: 100%">
</el-dialog>
</UserCenterLayout>
</div>

View File

@@ -11,6 +11,8 @@
<div class="goods-row" v-if="orderGoods.goodsName">
<img
:src="orderGoods.goodsImage"
loading="lazy"
decoding="async"
alt=""
@click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)"
@error="$event.target.style.visibility = 'hidden'"
@@ -47,6 +49,8 @@
v-for="(img, index) in orderGoods.images.split(',')"
:key="index"
:src="img"
loading="lazy"
decoding="async"
alt=""
@click="handleView(img)"
/>
@@ -61,6 +65,8 @@
v-for="(img, index) in orderGoods.replyImage.split(',')"
:key="index"
:src="img"
loading="lazy"
decoding="async"
alt=""
@click="handleView(img)"
/>
@@ -68,7 +74,7 @@
</div>
<el-dialog title="查看图片" v-model="visible" width="640px">
<img :src="previewImage" v-if="visible" class="preview-img" alt="" />
<img :src="previewImage" loading="lazy" decoding="async" v-if="visible" class="preview-img" alt="" />
</el-dialog>
</UserCenterLayout>
</div>

View File

@@ -43,6 +43,8 @@
@click="goodsDetail(order.skuId, order.goodsId)"
class="hover-color"
:src="order.goodsImage"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>
@@ -89,7 +91,7 @@
<div>
<div class="goods-list modal-goods">
<img @click="goodsDetail(singleOrder.skuId, singleOrder.goodsId)" class="hover-color"
:src="singleOrder.goodsImage" alt=""/>
:src="singleOrder.goodsImage" loading="lazy" decoding="async" alt=""/>
<div>
<div class="hover-color" @click="goodsDetail(singleOrder.skuId, singleOrder.goodsId)">
{{ singleOrder.goodsName }}

View File

@@ -19,7 +19,7 @@
</div>
</div>
<div class="goods-row">
<img :src="afterSale.goodsImage" alt="" @error="$event.target.style.visibility = 'hidden'">
<img :src="afterSale.goodsImage" loading="lazy" decoding="async" alt="" @error="$event.target.style.visibility = 'hidden'">
<div class="goods-info">
<div class="goods-name">{{ afterSale.goodsName }}</div>
<div class="store-line">
@@ -93,6 +93,8 @@
v-for="img in afterSale.afterSaleImage.split(',')"
:key="img"
:src="img"
loading="lazy"
decoding="async"
@click="perviewImg(img)"
class="hover-pointer"
alt=""

View File

@@ -5,7 +5,7 @@
<el-table-column label="商品名称">
<template #default="{ row }">
<div style="padding:5px;display:flex;">
<img :src="row.image" style="vertical-align: top;" width="60" height="60" alt="">
<img :src="row.image" loading="lazy" decoding="async" style="vertical-align: top;" width="60" height="60" alt="">
<span class="ml_10">{{ row.goodsName }}</span>
</div>
</template>
@@ -50,7 +50,7 @@
<div class="upload-section">
<div class="upload-row">
<div class="demo-upload-list" v-for="(img, index) in uploadList" :key="index">
<img :src="img">
<img :src="img" loading="lazy" decoding="async">
<div class="demo-upload-list-cover">
<el-icon @click="handleView(img)"><View /></el-icon>
<el-icon @click="handleRemove(index)"><Delete /></el-icon>
@@ -95,7 +95,7 @@
</el-form-item>
</el-form>
<el-dialog title="图片预览" v-model="visible">
<img :src="previewImage" v-if="visible" style="width: 100%">
<img :src="previewImage" loading="lazy" decoding="async" v-if="visible" style="width: 100%">
</el-dialog>
</div>
</UserCenterLayout>

View File

@@ -10,7 +10,7 @@
</div>
<div class="goods-eval">
<div class="goods-con">
<img :src="orderGoods.image" class="hover-pointer" alt="" width="100" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">
<img :src="orderGoods.image" loading="lazy" decoding="async" class="hover-pointer" alt="" width="100" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">
<p class="hover-pointer color999" @click="goGoodsDetail(orderGoods.skuId, orderGoods.goodsId)">{{orderGoods.goodsName}}</p>
<p>{{ $filters.unitPrice(orderGoods.goodsPrice, '¥') }}</p>
</div>
@@ -28,7 +28,7 @@
<div class="upload-section">
<div class="upload-row">
<div class="demo-upload-list" v-for="(img, index) in orderGoods.uploadList" :key="index">
<img :src="img">
<img :src="img" loading="lazy" decoding="async">
<div class="demo-upload-list-cover">
<el-icon @click="handleView(img)"><View /></el-icon>
<el-icon @click="handleRemove(index)"><Delete /></el-icon>
@@ -56,7 +56,7 @@
</div>
</div>
<el-dialog title="图片预览" v-model="visible">
<img :src="previewImage" v-if="visible" style="width: 100%">
<img :src="previewImage" loading="lazy" decoding="async" v-if="visible" style="width: 100%">
</el-dialog>
</UserCenterLayout>
</div>

View File

@@ -4,33 +4,33 @@
<template #extra>
<el-button type="primary" @click="add">添加新地址</el-button>
</template>
<div class="address-box" v-for="(item, index) in list" :key="index">
<div class="address-header">
<span>
{{ item.name }}
<el-tag class="ml_10 default-address-tag" v-if="item.isDefault">默认地址</el-tag>
<el-tag class="ml_10" v-if="item.alias" color="warning">{{item.alias}}</el-tag>
</span>
<div class="address-action">
<span @click="edit(item.id)"><el-icon><Edit /></el-icon>修改</span>
<span @click="del(item.id)"><el-icon><Delete /></el-icon>删除</span>
<div class="address-list" v-if="list.length">
<div class="address-box" v-for="(item, index) in list" :key="index">
<div class="address-header">
<div class="address-title">
<span class="address-name">{{ item.name }}</span>
<span class="address-mobile">{{ item.mobile }}</span>
<el-tag size="small" class="default-address-tag" v-if="item.isDefault">默认地址</el-tag>
<el-tag size="small" class="alias-tag" v-if="item.alias">{{item.alias}}</el-tag>
</div>
<div class="address-action">
<span @click="edit(item.id)"><el-icon><Edit /></el-icon>修改</span>
<span class="del-btn" @click="del(item.id)"><el-icon><Delete /></el-icon>删除</span>
</div>
</div>
<div class="address-content">
<p>
<span class="address-content-title">收货地区</span>
<span>{{ $filters.unitAddress(item.consigneeAddressPath) }}</span>
</p>
<p>
<span class="address-content-title">详细地址</span>
<span>{{ item.detail }}</span>
</p>
</div>
</div>
<div class="address-content">
<p>
<span class="address-content-title"> 收 货 人 :</span> {{ item.name }}
</p>
<p>
<span class="address-content-title">收货地区:</span>{{ $filters.unitAddress(item.consigneeAddressPath) }}
</p>
<p>
<span class="address-content-title">详细地址:</span> {{ item.detail }}
</p>
<p>
<span class="address-content-title">手机号码:</span> {{ item.mobile }}
</p>
</div>
</div>
<el-empty v-else description="暂无收货地址" />
</UserCenterLayout>
</div>
</template>
@@ -95,63 +95,110 @@ export default {
.wrapper {
margin-bottom: 40px;
}
.address-box {
padding: 15px;
margin: 0;
border-bottom: 1px solid $border_color;
margin-bottom: 16px;
padding: 18px 20px;
border: 1px solid #ebedf0;
border-radius: 8px;
background: #fff;
transition: box-shadow 0.2s ease, border-color 0.2s ease;
&:last-child {
border-bottom: 0;
margin-bottom: 0;
}
&:hover {
border-color: #dcdfe6;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
}
.address-header {
cursor: pointer;
height: 35px;
display: flex;
align-items: center;
justify-content: space-between;
@include title_color($light_title_color);
font-size: 18px;
padding-bottom: 12px;
border-bottom: 1px dashed #ebedf0;
}
.address-title {
display: flex;
align-items: center;
min-width: 0;
}
.address-name {
font-size: 16px;
font-weight: 600;
color: $light_title_color;
}
.address-mobile {
margin-left: 14px;
font-size: 14px;
color: #909399;
}
.address-content {
cursor: pointer;
padding-top: 6px;
font-size: 14px;
color: #606266;
> p {
padding: 12px 0;
display: flex;
padding: 6px 0;
line-height: 22px;
}
}
.address-content-title {
flex-shrink: 0;
width: 70px;
color: #909399;
}
.address-action {
display: flex;
align-items: center;
gap: 15px;
flex-shrink: 0;
gap: 16px;
margin-left: 16px;
span {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 14px;
color: $theme_color;
font-size: 13px;
color: #909399;
cursor: pointer;
transition: color 0.2s ease;
&:hover {
color: $theme_color;
}
.el-icon {
font-size: 14px;
}
}
.del-btn:hover {
color: #f56c6c;
}
}
.default-address-tag {
margin-left: 10px;
background-color: #fff3f2 !important;
border: 1px solid $theme_color !important;
color: $theme_color !important;
}
.alias-tag {
margin-left: 10px;
}
#map-container {
width: 500px;
height: 300px;

View File

@@ -54,6 +54,8 @@
@click="goodsDetail(goods.skuId, goods.goodsId)"
class="hover-color"
:src="goods.image"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>
@@ -132,6 +134,8 @@
@click="goodsDetail(goods.skuId, goods.goodsId)"
class="hover-color"
:src="goods.image"
loading="lazy"
decoding="async"
alt=""
@error="$event.target.style.visibility = 'hidden'"
/>

View File

@@ -216,6 +216,8 @@
<img
@click="goodsDetail(goods.skuId, goods.goodsId)"
:src="goods.image"
loading="lazy"
decoding="async"
alt=""
/>
<p

View File

@@ -13,7 +13,7 @@
@click="goodsDetail(item.id, item.goodsId)"
>
<div class="thumb">
<img :src="item.thumbnail" :alt="item.goodsName" />
<img :src="item.thumbnail" loading="lazy" decoding="async" :alt="item.goodsName" />
</div>
<p class="goods-name">{{ item.goodsName }}</p>
<p class="goods-price">{{ $filters.unitPrice(item.price, "¥") }}</p>

View File

@@ -18,7 +18,7 @@
@click="goGoodsDetail(item.id)"
>
<div class="goods-show-img">
<img :src="itemThumbnail(item)" />
<img :src="itemThumbnail(item)" loading="lazy" decoding="async" />
</div>
<div class="goods-show-price">
<span>

View File

@@ -29,7 +29,7 @@
<div v-else class="goods-show-info1" v-for="(item, index) in goodsList" :key="index"
@click="goGoodsDetail(item.skuId, item.goodsId)">
<div class="goods-show-img">
<img :src="item.goodsImage" :alt="item.goodsName" />
<img :src="item.goodsImage" loading="lazy" decoding="async" :alt="item.goodsName" />
</div>
<div class="goods-show-price">
<span class="seckill-price text-danger">{{ $filters.unitPrice(item.price, "¥") }}</span>