368 lines
8.0 KiB
Plaintext
368 lines
8.0 KiB
Plaintext
<template>
|
|
<view class="home-skeleton-root">
|
|
<view class="home-skeleton-header" :style="{ paddingTop: statusBarHeight + 'px' }">
|
|
<view class="home-skeleton-tab-row" :style="capsuleStyle">
|
|
<view class="home-skeleton-tab home-skeleton-tab-active skeleton-shimmer"></view>
|
|
<view class="home-skeleton-tab skeleton-shimmer"></view>
|
|
</view>
|
|
|
|
<view class="home-skeleton-search skeleton-shimmer">
|
|
<view class="home-skeleton-search-icon"></view>
|
|
<view class="home-skeleton-search-line"></view>
|
|
</view>
|
|
|
|
<scroll-view
|
|
v-if="showCategoryBar"
|
|
class="home-skeleton-category-scroll"
|
|
direction="horizontal"
|
|
:scroll-x="true"
|
|
:show-scrollbar="false"
|
|
>
|
|
<view class="home-skeleton-category-row">
|
|
<view
|
|
v-for="slot in categorySlots"
|
|
:key="'category-slot-' + slot"
|
|
:class="['home-skeleton-category-pill', 'skeleton-shimmer', slot == 0 ? 'home-skeleton-category-pill-active' : '']"
|
|
></view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="home-skeleton-body">
|
|
<view class="home-skeleton-banner skeleton-shimmer"></view>
|
|
|
|
<view class="home-skeleton-channel-grid">
|
|
<view
|
|
v-for="slot in channelSlots"
|
|
:key="'channel-slot-' + slot"
|
|
class="home-skeleton-channel-card"
|
|
>
|
|
<view class="home-skeleton-channel-icon skeleton-shimmer"></view>
|
|
<view class="home-skeleton-channel-line skeleton-shimmer"></view>
|
|
<view class="home-skeleton-channel-line home-skeleton-channel-line-short skeleton-shimmer"></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="home-skeleton-feed-header">
|
|
<view class="home-skeleton-feed-title skeleton-shimmer"></view>
|
|
<view class="home-skeleton-feed-subtitle skeleton-shimmer"></view>
|
|
</view>
|
|
|
|
<view class="home-skeleton-product-grid">
|
|
<view
|
|
v-for="slot in productSlots"
|
|
:key="'product-slot-' + slot"
|
|
class="home-skeleton-product-card"
|
|
>
|
|
<view class="home-skeleton-product-image skeleton-shimmer"></view>
|
|
<view class="home-skeleton-product-body">
|
|
<view class="home-skeleton-product-line skeleton-shimmer"></view>
|
|
<view class="home-skeleton-product-line home-skeleton-product-line-short skeleton-shimmer"></view>
|
|
<view class="home-skeleton-product-price-row">
|
|
<view class="home-skeleton-product-price skeleton-shimmer"></view>
|
|
<view class="home-skeleton-product-origin skeleton-shimmer"></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="home-skeleton-safe-bottom" :style="{ height: bottomSafeArea + 88 + 'px' }"></view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { computed } from 'vue'
|
|
|
|
const props = defineProps({
|
|
statusBarHeight: {
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
capsuleRight: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
bottomSafeArea: {
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
showCategoryBar: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
categoryCount: {
|
|
type: Number,
|
|
default: 7
|
|
},
|
|
channelCount: {
|
|
type: Number,
|
|
default: 4
|
|
},
|
|
productCount: {
|
|
type: Number,
|
|
default: 8
|
|
}
|
|
})
|
|
|
|
const capsuleStyle = computed((): string => props.capsuleRight > 0 ? `padding-right:${props.capsuleRight}px;` : '')
|
|
|
|
function buildSlots(total: number): Array<number> {
|
|
const slots: Array<number> = []
|
|
for (let i = 0; i < total; i++) {
|
|
slots.push(i)
|
|
}
|
|
return slots
|
|
}
|
|
|
|
const categorySlots = computed((): Array<number> => buildSlots(props.categoryCount))
|
|
const channelSlots = computed((): Array<number> => buildSlots(props.channelCount))
|
|
const productSlots = computed((): Array<number> => buildSlots(props.productCount))
|
|
</script>
|
|
|
|
<style scoped>
|
|
.home-skeleton-root {
|
|
min-height: 100%;
|
|
background: linear-gradient(180deg, #f6f8fb 0%, #f9fafc 42%, #f4f6f8 100%);
|
|
}
|
|
|
|
.home-skeleton-header {
|
|
padding-left: 24rpx;
|
|
padding-right: 24rpx;
|
|
padding-bottom: 20rpx;
|
|
background: linear-gradient(180deg, #f6f8fb 0%, rgba(246, 248, 251, 0.98) 100%);
|
|
}
|
|
|
|
.home-skeleton-tab-row {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding-left: 20rpx;
|
|
padding-right: 24rpx;
|
|
height: 62rpx;
|
|
box-sizing: border-box;
|
|
padding-top: 6rpx;
|
|
padding-bottom: 18rpx;
|
|
}
|
|
|
|
.home-skeleton-tab {
|
|
min-width: 132rpx;
|
|
height: 56rpx;
|
|
border-radius: 999rpx;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #eceff3;
|
|
border-width: 2rpx;
|
|
border-style: solid;
|
|
border-color: transparent;
|
|
padding-left: 24rpx;
|
|
padding-right: 24rpx;
|
|
box-sizing: border-box;
|
|
margin-right: 20rpx;
|
|
}
|
|
|
|
.home-skeleton-tab-active {
|
|
border-color: rgba(215, 39, 39, 0.16);
|
|
background-color: #fef2f2;
|
|
box-shadow: 0 10rpx 22rpx rgba(215, 39, 39, 0.08);
|
|
}
|
|
|
|
.home-skeleton-search {
|
|
height: 72rpx;
|
|
border-radius: 999rpx;
|
|
background-color: #eceff3;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding-left: 24rpx;
|
|
padding-right: 24rpx;
|
|
box-sizing: border-box;
|
|
margin-bottom: 18rpx;
|
|
box-shadow: 0 10rpx 24rpx rgba(15, 23, 42, 0.04);
|
|
}
|
|
|
|
.home-skeleton-search-icon {
|
|
width: 26rpx;
|
|
height: 26rpx;
|
|
border-radius: 13rpx;
|
|
background-color: rgba(176, 184, 196, 0.55);
|
|
margin-right: 14rpx;
|
|
}
|
|
|
|
.home-skeleton-search-line {
|
|
height: 24rpx;
|
|
width: 320rpx;
|
|
border-radius: 12rpx;
|
|
background-color: rgba(176, 184, 196, 0.45);
|
|
}
|
|
|
|
.home-skeleton-category-scroll {
|
|
width: 100%;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.home-skeleton-category-row {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding-bottom: 8rpx;
|
|
padding-right: 24rpx;
|
|
gap: 18rpx;
|
|
}
|
|
|
|
.home-skeleton-category-pill {
|
|
width: 112rpx;
|
|
height: 44rpx;
|
|
border-radius: 999rpx;
|
|
background-color: #eceff3;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.home-skeleton-category-pill-active {
|
|
width: 128rpx;
|
|
background-color: #f3f4f6;
|
|
}
|
|
|
|
.home-skeleton-body {
|
|
padding: 20rpx 24rpx 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.home-skeleton-banner {
|
|
height: 180rpx;
|
|
border-radius: 28rpx;
|
|
background-color: #eceff3;
|
|
margin-bottom: 22rpx;
|
|
box-shadow: 0 14rpx 28rpx rgba(15, 23, 42, 0.04);
|
|
}
|
|
|
|
.home-skeleton-channel-grid {
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
margin-bottom: 28rpx;
|
|
row-gap: 18rpx;
|
|
}
|
|
|
|
.home-skeleton-channel-card {
|
|
width: 164rpx;
|
|
border-radius: 24rpx;
|
|
background-color: #ffffff;
|
|
padding-top: 24rpx;
|
|
padding-bottom: 20rpx;
|
|
align-items: center;
|
|
box-shadow: 0 10rpx 22rpx rgba(15, 23, 42, 0.04);
|
|
}
|
|
|
|
.home-skeleton-channel-icon {
|
|
width: 76rpx;
|
|
height: 76rpx;
|
|
border-radius: 38rpx;
|
|
background-color: #eceff3;
|
|
margin-bottom: 14rpx;
|
|
}
|
|
|
|
.home-skeleton-channel-line {
|
|
width: 94rpx;
|
|
height: 20rpx;
|
|
border-radius: 10rpx;
|
|
background-color: #eceff3;
|
|
margin-top: 8rpx;
|
|
}
|
|
|
|
.home-skeleton-channel-line-short {
|
|
width: 66rpx;
|
|
}
|
|
|
|
.home-skeleton-feed-header {
|
|
margin-bottom: 22rpx;
|
|
}
|
|
|
|
.home-skeleton-feed-title {
|
|
width: 180rpx;
|
|
height: 28rpx;
|
|
border-radius: 14rpx;
|
|
background-color: #eceff3;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.home-skeleton-feed-subtitle {
|
|
width: 240rpx;
|
|
height: 20rpx;
|
|
border-radius: 10rpx;
|
|
background-color: #eceff3;
|
|
}
|
|
|
|
.home-skeleton-product-grid {
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
row-gap: 20rpx;
|
|
}
|
|
|
|
.home-skeleton-product-card {
|
|
width: 340rpx;
|
|
border-radius: 28rpx;
|
|
background-color: #ffffff;
|
|
overflow: hidden;
|
|
box-shadow: 0 12rpx 26rpx rgba(15, 23, 42, 0.05);
|
|
}
|
|
|
|
.home-skeleton-product-image {
|
|
height: 340rpx;
|
|
background-color: #eceff3;
|
|
}
|
|
|
|
.home-skeleton-product-body {
|
|
padding: 18rpx 18rpx 22rpx;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.home-skeleton-product-line {
|
|
height: 24rpx;
|
|
border-radius: 12rpx;
|
|
background-color: #eceff3;
|
|
margin-bottom: 14rpx;
|
|
}
|
|
|
|
.home-skeleton-product-line-short {
|
|
width: 72%;
|
|
}
|
|
|
|
.home-skeleton-product-price-row {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-top: 18rpx;
|
|
}
|
|
|
|
.home-skeleton-product-price {
|
|
width: 128rpx;
|
|
height: 28rpx;
|
|
border-radius: 14rpx;
|
|
background-color: #eceff3;
|
|
}
|
|
|
|
.home-skeleton-product-origin {
|
|
width: 88rpx;
|
|
height: 20rpx;
|
|
border-radius: 10rpx;
|
|
background-color: #eceff3;
|
|
}
|
|
|
|
.home-skeleton-safe-bottom {
|
|
width: 100%;
|
|
}
|
|
|
|
.skeleton-shimmer {
|
|
background: linear-gradient(90deg, #edf0f4 0%, #f9fbfd 48%, #edf0f4 100%);
|
|
background-size: 220% 100%;
|
|
animation: skeleton-shimmer 1.35s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes skeleton-shimmer {
|
|
0% {
|
|
background-position: 200% 0;
|
|
}
|
|
100% {
|
|
background-position: -20% 0;
|
|
}
|
|
}
|
|
</style> |