feat: ✨ 商品详情页添加骨架屏
This commit is contained in:
parent
1ef33c2f70
commit
f137109b12
221
src/pages/goods/components/PageSkeleton.vue
Normal file
221
src/pages/goods/components/PageSkeleton.vue
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
<template name="skeleton">
|
||||||
|
<view class="sk-container">
|
||||||
|
<scroll-view :scroll-y="true" class="viewport viewport" :enable-back-to-top="true">
|
||||||
|
<view class="goods goods">
|
||||||
|
<view class="preview preview">
|
||||||
|
<swiper :circular="true" class="swiper swiper" :current="0" :autoplay="false">
|
||||||
|
<swiper-item
|
||||||
|
style="
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: translate(0%, 0px) translateZ(0px);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<image class="image sk-image" mode="aspectFill"></image>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
<view class="indicator indicator">
|
||||||
|
<text class="current sk-transparent sk-opacity">1</text>
|
||||||
|
<text class="split sk-transparent sk-opacity">/</text>
|
||||||
|
<text class="total sk-transparent sk-opacity">4</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="meta meta">
|
||||||
|
<view class="price price">
|
||||||
|
<text class="symbol sk-transparent sk-opacity">¥</text>
|
||||||
|
<text class="number sk-transparent sk-text-14-2857-867 sk-text">128.00</text>
|
||||||
|
</view>
|
||||||
|
<view class="name ellipsis sk-transparent sk-text-14-2857-403 sk-text"
|
||||||
|
>钻石陶瓷涂层多用锅18cm 小奶锅</view
|
||||||
|
>
|
||||||
|
<view class="desc sk-transparent sk-text-0-0000-460 sk-text">安全耐用,易于清洗APP</view>
|
||||||
|
</view>
|
||||||
|
<view class="action action">
|
||||||
|
<view class="item arrow sk-pseudo sk-pseudo-circle">
|
||||||
|
<text class="label sk-transparent sk-text-14-2857-126 sk-text">选择</text>
|
||||||
|
<text class="text ellipsis sk-transparent sk-text-14-2857-698 sk-text">
|
||||||
|
请选择商品规格
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow sk-pseudo sk-pseudo-circle">
|
||||||
|
<text class="label sk-transparent sk-text-14-2857-337 sk-text">送至</text>
|
||||||
|
<text class="text ellipsis sk-transparent sk-text-14-2857-169 sk-text">
|
||||||
|
请选择收货地址
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow sk-pseudo sk-pseudo-circle"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="toolbar toolbar" style="padding-bottom: 0px">
|
||||||
|
<view class="icons icons">
|
||||||
|
<button class="icons-button sk-transparent sk-button sk-pseudo sk-pseudo-circle">
|
||||||
|
<text class="icon-heart sk-pseudo sk-pseudo-circle"></text>收藏
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="icons-button sk-transparent sk-button sk-pseudo sk-pseudo-circle"
|
||||||
|
open-type="contact"
|
||||||
|
>
|
||||||
|
<text class="icon-handset sk-pseudo sk-pseudo-circle"></text>客服
|
||||||
|
</button>
|
||||||
|
<navigator class="icons-button sk-transparent" open-type="switchTab">
|
||||||
|
<text class="icon-cart sk-pseudo sk-pseudo-circle"></text>购物车
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
<view class="buttons buttons">
|
||||||
|
<view
|
||||||
|
class="addcart sk-transparent sk-text-31-9444-431 sk-text"
|
||||||
|
style="background-position-x: 50%"
|
||||||
|
>
|
||||||
|
加入购物车
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="buynow sk-transparent sk-text-31-9444-819 sk-text"
|
||||||
|
style="background-position-x: 50%"
|
||||||
|
>
|
||||||
|
立即购买
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sk-transparent {
|
||||||
|
color: transparent !important;
|
||||||
|
}
|
||||||
|
.sk-opacity {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-867 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 78.4rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text {
|
||||||
|
background-origin: content-box !important;
|
||||||
|
background-clip: content-box !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: transparent !important;
|
||||||
|
background-repeat: repeat-y !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-403 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 44.8rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-0-0000-460 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 0%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 100%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 24rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-126 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 36.4rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-698 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 36.4rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-337 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 36.4rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-14-2857-169 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 14.2857%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 85.7143%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 36.4rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-31-9444-431 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 31.9444%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 68.0556%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 72rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-text-31-9444-819 {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
transparent 31.9444%,
|
||||||
|
#eeeeee 0%,
|
||||||
|
#eeeeee 68.0556%,
|
||||||
|
transparent 0%
|
||||||
|
) !important;
|
||||||
|
background-size: 100% 72rpx;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.sk-button {
|
||||||
|
color: #efefef !important;
|
||||||
|
background: #efefef !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.sk-image {
|
||||||
|
background: #efefef !important;
|
||||||
|
}
|
||||||
|
.sk-pseudo::before,
|
||||||
|
.sk-pseudo::after {
|
||||||
|
background: #efefef !important;
|
||||||
|
background-image: none !important;
|
||||||
|
color: transparent !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
.sk-pseudo-rect::before,
|
||||||
|
.sk-pseudo-rect::after {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
.sk-pseudo-circle::before,
|
||||||
|
.sk-pseudo-circle::after {
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
.sk-container {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,118 +1,121 @@
|
|||||||
<template>
|
<template>
|
||||||
<scroll-view scroll-y class="viewport">
|
<PageSkeleton v-if="isLoading" />
|
||||||
<!-- 基本信息 -->
|
<template v-else>
|
||||||
<view class="goods">
|
<scroll-view scroll-y class="viewport">
|
||||||
<!-- 商品主图 -->
|
<!-- 基本信息 -->
|
||||||
<view class="preview">
|
<view class="goods">
|
||||||
<swiper circular class="swiper" @change="handlerChange">
|
<!-- 商品主图 -->
|
||||||
<swiper-item v-for="item in goods?.mainPictures" :key="item">
|
<view class="preview">
|
||||||
<image mode="aspectFill" :src="item" class="image" />
|
<swiper circular class="swiper" @change="handlerChange">
|
||||||
</swiper-item>
|
<swiper-item v-for="item in goods?.mainPictures" :key="item">
|
||||||
</swiper>
|
<image mode="aspectFill" :src="item" class="image" />
|
||||||
<view class="indicator">
|
</swiper-item>
|
||||||
<text class="current">{{ currentIndex + 1 }}</text>
|
</swiper>
|
||||||
<text class="split">/</text>
|
<view class="indicator">
|
||||||
<text class="total">{{ goods?.mainPictures.length }}</text>
|
<text class="current">{{ currentIndex + 1 }}</text>
|
||||||
</view>
|
<text class="split">/</text>
|
||||||
</view>
|
<text class="total">{{ goods?.mainPictures.length }}</text>
|
||||||
|
|
||||||
<!-- 商品简介 -->
|
|
||||||
<view class="meta">
|
|
||||||
<view class="price">
|
|
||||||
<text class="symbol">¥</text>
|
|
||||||
<text class="number">{{ goods?.price }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="name ellipsis"> {{ goods?.name }} </view>
|
|
||||||
<view class="desc"> {{ goods?.desc }} </view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 操作面板 -->
|
|
||||||
<view class="action">
|
|
||||||
<view class="item arrow">
|
|
||||||
<text class="label">选择</text>
|
|
||||||
<text class="text ellipsis"> 请选择商品规格 </text>
|
|
||||||
</view>
|
|
||||||
<view class="item arrow" @tap="showPopup('address')">
|
|
||||||
<text class="label">送至</text>
|
|
||||||
<text class="text ellipsis"> 请选择收货地址 </text>
|
|
||||||
</view>
|
|
||||||
<view class="item arrow" @tap="showPopup('service')">
|
|
||||||
<text class="label">服务</text>
|
|
||||||
<text class="text ellipsis"> 无忧退 快速退款 免费包邮 </text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 商品详情 -->
|
|
||||||
<view class="detail panel">
|
|
||||||
<view class="title">
|
|
||||||
<text>详情</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<view class="properties">
|
|
||||||
<!-- 属性详情 -->
|
|
||||||
<view class="item" v-for="item in goods?.details.properties" :key="item.name">
|
|
||||||
<text class="label">{{ item.name }}</text>
|
|
||||||
<text class="value">{{ item.value }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 图片详情 -->
|
|
||||||
<image
|
|
||||||
mode="widthFix"
|
|
||||||
class="image"
|
|
||||||
:src="item"
|
|
||||||
v-for="(item, index) in goods?.details.pictures"
|
|
||||||
:key="item + index"
|
|
||||||
></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 同类推荐 -->
|
<!-- 商品简介 -->
|
||||||
<view class="similar panel">
|
<view class="meta">
|
||||||
<view class="title">
|
|
||||||
<text>同类推荐</text>
|
|
||||||
</view>
|
|
||||||
<view class="content">
|
|
||||||
<navigator
|
|
||||||
v-for="item in goods?.similarProducts"
|
|
||||||
:key="item.id"
|
|
||||||
class="goods"
|
|
||||||
hover-class="none"
|
|
||||||
:url="`/pages/goods/goods?id=${item.id}`"
|
|
||||||
>
|
|
||||||
<image class="image" mode="widthFix" :src="item.picture"></image>
|
|
||||||
<view class="name ellipsis">{{ item.name }}</view>
|
|
||||||
<view class="price">
|
<view class="price">
|
||||||
<text class="symbol">¥</text>
|
<text class="symbol">¥</text>
|
||||||
<text class="number">{{ item.price }}</text>
|
<text class="number">{{ goods?.price }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="name ellipsis"> {{ goods?.name }} </view>
|
||||||
|
<view class="desc"> {{ goods?.desc }} </view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 操作面板 -->
|
||||||
|
<view class="action">
|
||||||
|
<view class="item arrow">
|
||||||
|
<text class="label">选择</text>
|
||||||
|
<text class="text ellipsis"> 请选择商品规格 </text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow" @tap="showPopup('address')">
|
||||||
|
<text class="label">送至</text>
|
||||||
|
<text class="text ellipsis"> 请选择收货地址 </text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow" @tap="showPopup('service')">
|
||||||
|
<text class="label">服务</text>
|
||||||
|
<text class="text ellipsis"> 无忧退 快速退款 免费包邮 </text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品详情 -->
|
||||||
|
<view class="detail panel">
|
||||||
|
<view class="title">
|
||||||
|
<text>详情</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="properties">
|
||||||
|
<!-- 属性详情 -->
|
||||||
|
<view class="item" v-for="item in goods?.details.properties" :key="item.name">
|
||||||
|
<text class="label">{{ item.name }}</text>
|
||||||
|
<text class="value">{{ item.value }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 图片详情 -->
|
||||||
|
<image
|
||||||
|
mode="widthFix"
|
||||||
|
class="image"
|
||||||
|
:src="item"
|
||||||
|
v-for="(item, index) in goods?.details.pictures"
|
||||||
|
:key="item + index"
|
||||||
|
></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 同类推荐 -->
|
||||||
|
<view class="similar panel">
|
||||||
|
<view class="title">
|
||||||
|
<text>同类推荐</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<navigator
|
||||||
|
v-for="item in goods?.similarProducts"
|
||||||
|
:key="item.id"
|
||||||
|
class="goods"
|
||||||
|
hover-class="none"
|
||||||
|
:url="`/pages/goods/goods?id=${item.id}`"
|
||||||
|
>
|
||||||
|
<image class="image" mode="widthFix" :src="item.picture"></image>
|
||||||
|
<view class="name ellipsis">{{ item.name }}</view>
|
||||||
|
<view class="price">
|
||||||
|
<text class="symbol">¥</text>
|
||||||
|
<text class="number">{{ item.price }}</text>
|
||||||
|
</view>
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 用户操作 -->
|
||||||
|
<view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
|
||||||
|
<view class="icons">
|
||||||
|
<button class="icons-button"><text class="icon-heart"></text>收藏</button>
|
||||||
|
<button class="icons-button" open-type="contact">
|
||||||
|
<text class="icon-handset"></text>客服
|
||||||
|
</button>
|
||||||
|
<navigator class="icons-button" url="/pages/cart/cart" open-type="switchTab">
|
||||||
|
<text class="icon-cart"></text>购物车
|
||||||
</navigator>
|
</navigator>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="buttons">
|
||||||
|
<view class="addcart"> 加入购物车 </view>
|
||||||
|
<view class="buynow"> 立即购买 </view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
<!-- 用户操作 -->
|
<!-- 弹出层 -->
|
||||||
<view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
|
<uni-popup ref="popup" type="bottom" background-color="#fff">
|
||||||
<view class="icons">
|
<AddressPanel v-if="popupType === 'address'" @close="handlerClose" />
|
||||||
<button class="icons-button"><text class="icon-heart"></text>收藏</button>
|
<ServicePanel v-if="popupType === 'service'" @close="handlerClose" />
|
||||||
<button class="icons-button" open-type="contact">
|
</uni-popup>
|
||||||
<text class="icon-handset"></text>客服
|
</template>
|
||||||
</button>
|
|
||||||
<navigator class="icons-button" url="/pages/cart/cart" open-type="switchTab">
|
|
||||||
<text class="icon-cart"></text>购物车
|
|
||||||
</navigator>
|
|
||||||
</view>
|
|
||||||
<view class="buttons">
|
|
||||||
<view class="addcart"> 加入购物车 </view>
|
|
||||||
<view class="buynow"> 立即购买 </view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 弹出层 -->
|
|
||||||
<uni-popup ref="popup" type="bottom" background-color="#fff">
|
|
||||||
<AddressPanel v-if="popupType === 'address'" @close="handlerClose" />
|
|
||||||
<ServicePanel v-if="popupType === 'service'" @close="handlerClose" />
|
|
||||||
</uni-popup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -122,6 +125,7 @@ import { onLoad } from '@dcloudio/uni-app'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import ServicePanel from './components/ServicePanel.vue'
|
import ServicePanel from './components/ServicePanel.vue'
|
||||||
import AddressPanel from './components/AddressPanel.vue'
|
import AddressPanel from './components/AddressPanel.vue'
|
||||||
|
import PageSkeleton from './components/PageSkeleton.vue'
|
||||||
|
|
||||||
// 获取屏幕边界到安全区域距离
|
// 获取屏幕边界到安全区域距离
|
||||||
const { safeAreaInsets } = uni.getSystemInfoSync()
|
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||||
@ -171,8 +175,12 @@ const handlerClose = () => {
|
|||||||
popup.value?.close()
|
popup.value?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad(() => {
|
// 添加骨架屏
|
||||||
getGoods()
|
const isLoading = ref(true)
|
||||||
|
|
||||||
|
onLoad(async () => {
|
||||||
|
await getGoods()
|
||||||
|
isLoading.value = false
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user