Files

348 lines
7.3 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!--
列表骨架屏 type 模拟医生卡/消息行/商品卡/资讯卡/分类侧栏/商品详情
放在分包以控制主包体积主包页通过 componentPlaceholder 异步引用
-->
<view class="list-skeleton" :class="'list-skeleton--' + type">
<!-- 商品详情整页一块骨架不按 rows 循环 -->
<template v-if="type === 'detail'">
<view class="sk-detail-hero sk-shimmer"></view>
<view class="sk-detail-basic">
<view class="sk-line sk-line--price sk-shimmer"></view>
<view class="sk-line sk-line--lg sk-shimmer"></view>
<view class="sk-line sk-line--md sk-shimmer"></view>
<view class="sk-detail-spec">
<view class="sk-line sk-line--sm sk-shimmer"></view>
<view class="sk-line sk-line--sm sk-shimmer"></view>
</view>
</view>
<view class="sk-detail-tip sk-shimmer"></view>
<!-- H5 :key 仅支持简单变量禁止 'card-'+i 拼接 -->
<view
v-for="i in detailCardCount"
:key="i"
class="sk-detail-card"
>
<view class="sk-line sk-line--md sk-shimmer"></view>
<view class="sk-line sk-line--sm sk-shimmer"></view>
<view class="sk-line sk-line--lg sk-shimmer"></view>
</view>
</template>
<!-- 列表类骨架按 rows 循环 -->
<template v-else>
<view
v-for="i in rowCount"
:key="i"
class="sk-row"
:class="'sk-row--' + type"
>
<!-- 医生推荐卡片 -->
<template v-if="type === 'doctor'">
<view class="sk-avatar sk-shimmer"></view>
<view class="sk-body">
<view class="sk-line sk-line--lg sk-shimmer"></view>
<view class="sk-line sk-line--md sk-shimmer"></view>
<view class="sk-line sk-line--sm sk-shimmer"></view>
</view>
</template>
<!-- 消息列表行 -->
<template v-else-if="type === 'message'">
<view class="sk-avatar sk-avatar--round sk-shimmer"></view>
<view class="sk-body">
<view class="sk-line-row">
<view class="sk-line sk-line--md sk-shimmer"></view>
<view class="sk-line sk-line--xs sk-shimmer"></view>
</view>
<view class="sk-line sk-line--sm sk-shimmer"></view>
</view>
</template>
<!-- 商品卡片 -->
<template v-else-if="type === 'product'">
<view class="sk-prod-img sk-shimmer"></view>
<view class="sk-body">
<view class="sk-line sk-line--lg sk-shimmer"></view>
<view class="sk-line sk-line--sm sk-shimmer"></view>
<view class="sk-line sk-line--md sk-shimmer"></view>
</view>
</template>
<!-- 资讯文章卡片 -->
<template v-else-if="type === 'article'">
<view class="sk-cover sk-shimmer"></view>
<view class="sk-cover-title sk-shimmer"></view>
</template>
<!-- 资讯左侧分类 -->
<template v-else-if="type === 'category'">
<view class="sk-cate-item sk-shimmer"></view>
</template>
<!-- 金刚区横滑块 -->
<template v-else-if="type === 'zone'">
<view class="sk-zone-icon sk-shimmer"></view>
<view class="sk-line sk-line--xs sk-shimmer"></view>
</template>
</view>
</template>
</view>
</template>
<script>
export default {
name: 'ListSkeleton',
props: {
// 骨架样式类型detail 为商品详情整页骨架)
type: {
type: String,
default: 'message',
validator(v) {
return ['doctor', 'message', 'product', 'article', 'category', 'zone', 'detail'].indexOf(v) !== -1
}
},
// 行数detail 时表示信息卡片块数)
rows: {
type: [Number, String],
default: 3
}
},
computed: {
rowCount() {
const n = Number(this.rows)
return n > 0 ? n : 3
},
// 详情骨架信息卡数量,默认 3 块
detailCardCount() {
return this.rowCount
}
}
}
</script>
<style lang="scss" scoped>
.list-skeleton {
width: 100%;
}
.sk-shimmer {
background: linear-gradient(90deg, #ebebeb 25%, #f5f5f5 50%, #ebebeb 75%);
background-size: 400% 100%;
animation: sk-shimmer 1.4s ease infinite;
}
@keyframes sk-shimmer {
0% {
background-position: 100% 0;
}
100% {
background-position: 0 0;
}
}
.sk-row--doctor {
display: flex;
align-items: flex-start;
margin: 0 24rpx 20rpx;
padding: 28rpx;
background: #fff;
border-radius: 24rpx;
.sk-avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
flex-shrink: 0;
margin-right: 20rpx;
}
.sk-body {
flex: 1;
}
}
.sk-row--message {
display: flex;
align-items: center;
padding: 32rpx 38rpx;
background: #fff;
.sk-avatar {
width: 84rpx;
height: 84rpx;
border-radius: 50%;
flex-shrink: 0;
margin-right: 24rpx;
}
.sk-body {
flex: 1;
}
.sk-line-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
}
}
.sk-row--product {
display: flex;
margin: 0 24rpx 20rpx;
padding: 20rpx;
background: #fff;
border-radius: 16rpx;
.sk-prod-img {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
flex-shrink: 0;
margin-right: 20rpx;
}
.sk-body {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
.sk-row--article {
position: relative;
width: 500rpx;
height: 246rpx;
margin: 10rpx auto;
border-radius: 12rpx;
overflow: hidden;
.sk-cover {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.sk-cover-title {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 92rpx;
opacity: 0.5;
}
}
.sk-row--category {
width: 184rpx;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
.sk-cate-item {
width: 100rpx;
height: 28rpx;
border-radius: 6rpx;
}
}
.list-skeleton--zone {
display: flex;
flex-wrap: nowrap;
padding: 16rpx 24rpx;
overflow: hidden;
}
.sk-row--zone {
display: flex;
flex-direction: column;
align-items: center;
width: 140rpx;
flex-shrink: 0;
margin-right: 16rpx;
.sk-zone-icon {
width: 88rpx;
height: 88rpx;
border-radius: 20rpx;
margin-bottom: 12rpx;
}
.sk-line--xs {
width: 72rpx;
}
}
.sk-line {
height: 24rpx;
border-radius: 6rpx;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
.sk-line--lg {
width: 70%;
}
.sk-line--md {
width: 50%;
}
.sk-line--sm {
width: 90%;
}
.sk-line--xs {
width: 80rpx;
height: 20rpx;
margin-bottom: 0;
}
.sk-line-row .sk-line--md {
width: 40%;
margin-bottom: 0;
}
/* 商品详情骨架:大图 + 基础信息 + 物流条 + 信息卡 */
.list-skeleton--detail {
background: #F5F7FA;
min-height: 100vh;
padding-bottom: 40rpx;
}
.sk-detail-hero {
width: 100%;
height: 750rpx;
}
.sk-detail-basic {
background: #fff;
padding: 32rpx 30rpx;
margin-bottom: 20rpx;
.sk-line--price {
width: 200rpx;
height: 48rpx;
margin-bottom: 24rpx;
}
}
.sk-detail-spec {
margin-top: 24rpx;
padding-top: 16rpx;
}
.sk-detail-tip {
height: 80rpx;
margin: 0 0 20rpx;
border-radius: 0;
}
.sk-detail-card {
background: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
</style>