列表骨架屏

This commit is contained in:
juguohong
2025-08-24 19:58:00 +08:00
parent cda1a4b7cc
commit 58bacb3a47
13 changed files with 532 additions and 249 deletions

View File

@@ -0,0 +1,28 @@
import PopupGameplay from "../../pages/publishBall/components/PopupGameplay";
import { View, Text, Image } from "@tarojs/components";
import TitleComponent from "@/components/Title";
import img from "@/config/images";
const GamePlayType = () => {
return (
<View>
<TitleComponent title="玩法" icon={<Image src={img.ICON_SITE} />} />
<PopupGameplay
onClose={() => {
console.log("onClose");
}}
onConfirm={() => {
console.log("onConfirm");
}}
visible={false}
options={[
{ label: "不限", value: "不限" },
{ label: "单打", value: "单打" },
{ label: "双打", value: "双打" },
{ label: "拉球", value: "拉球" },
]}
/>
</View>
);
};
export default GamePlayType;

View File

@@ -1,16 +1,17 @@
.list-item {
display: flex;
padding: 16px;
padding: 12px 15px;
background: #ffffff;
border-radius: 20px;
border: 0.5px solid #f0f0f0;
justify-content: space-between;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
gap: 6px;
width: calc(100% - 122px);
}
.titleWrapper {
@@ -23,19 +24,40 @@
font-weight: 600;
color: #000000;
line-height: 24px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.title-right-arrow {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.date-time,
.location {
display: flex;
align-items: center;
}
.location-position {
max-width: 66%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.location-text {
display: block;
}
.date-time {
font-size: 12px;
color: #3C3C4399;
font-weight: 400;
line-height: 18px;
margin-top: 6px;
margin-bottom: 4px;
}
.bottom-info {

View File

@@ -1,20 +1,10 @@
import { View, Text, Image } from "@tarojs/components";
import img from "../../config/images";
import { ListCardProps } from "../../../types/list/types";
import "./index.scss";
// import SkeletonComponent from "../../components/Skeleton";
interface ListItemProps {
title: string;
dateTime: string;
location: string;
distance: string;
registeredCount: number;
maxCount: number;
skillLevel: string;
matchType: string;
images: string[];
}
const ListItem: React.FC<ListItemProps> = ({
const ListCard: React.FC<ListCardProps> = ({
title,
dateTime,
location,
@@ -24,7 +14,12 @@ const ListItem: React.FC<ListItemProps> = ({
skillLevel,
matchType,
images,
shinei,
}) => {
const renderItemImage = (src: string) => {
return <Image src={src} className="image" mode="aspectFill" />;
};
// 根据图片数量决定展示样式
const renderImages = () => {
if (images.length === 0) return null;
@@ -33,7 +28,8 @@ const ListItem: React.FC<ListItemProps> = ({
return (
<View className="single-image">
<View className="image-container">
<Image src={images[0]} className="image" mode="aspectFill" />
{/* <Image src={images[0]} className="image" mode="aspectFill" /> */}
{renderItemImage(images[0])}
</View>
</View>
);
@@ -43,10 +39,12 @@ const ListItem: React.FC<ListItemProps> = ({
return (
<View className="double-image">
<View className="image-container">
<Image src={images[0]} className="image" mode="aspectFill" />
{/* <Image src={images[0]} className="image" mode="aspectFill" /> */}
{renderItemImage(images[0])}
</View>
<View className="image-container">
<Image src={images[1]} className="image" mode="aspectFill" />
{/* <Image src={images[1]} className="image" mode="aspectFill" /> */}
{renderItemImage(images[1])}
</View>
</View>
);
@@ -55,19 +53,13 @@ const ListItem: React.FC<ListItemProps> = ({
// 3张或更多图片
return (
<View className="triple-image">
<View className="image-container">
<Image src={images[0]} className="image" mode="aspectFill" />
</View>
<View className="image-container">
<Image src={images[1]} className="image" mode="aspectFill" />
</View>
<View className="image-container">
<Image src={images[2]} className="image" mode="aspectFill" />
</View>
<View className="image-container">{renderItemImage(images[0])}</View>
<View className="image-container">{renderItemImage(images[1])}</View>
<View className="image-container">{renderItemImage(images[2])}</View>
</View>
);
};
console.log("===ttt", !title);
return (
<View className="list-item">
{/* 左侧内容区域 */}
@@ -83,12 +75,20 @@ const ListItem: React.FC<ListItemProps> = ({
</View>
{/* 时间信息 */}
<Text className="date-time">{dateTime}</Text>
{/* 地点和距离 */}
<Text className="location">
{location}{distance}
</Text>
<View className="date-time">
<Text>{dateTime}</Text>
</View>
{/* 地点,室内外,距离 */}
<View className="location">
<Text className="location-text location-position">{location}</Text>
<Text className="location-text location-time-distance">
{shinei && `${shinei}`}
{distance && `${distance}`}
</Text>
</View>
{/* 底部信息行:头像组、报名人数、技能等级、比赛类型 */}
<View className="bottom-info">
@@ -131,4 +131,4 @@ const ListItem: React.FC<ListItemProps> = ({
);
};
export default ListItem;
export default ListCard;

View File

@@ -0,0 +1,264 @@
.list-item {
display: flex;
padding: 12px 15px;
background: #ffffff;
border-radius: 20px;
border: 0.5px solid #f0f0f0;
justify-content: space-between;
--nutui-skeleton-line-height: 24px;
--nutui-skeleton-line-border-radius: 24px;
.nut-skeleton-block {
margin: 0;
}
}
.content {
flex: 1;
display: flex;
flex-direction: column;
width: calc(100% - 122px);
}
.titleWrapper {
display: flex;
align-items: center;
}
.title {
font-size: 16px;
font-weight: 600;
color: #000000;
line-height: 24px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.title-right-arrow {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.location {
display: flex;
align-items: center;
}
.location-position {
max-width: 66%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.location-text {
display: block;
}
.date-time {
font-size: 12px;
color: #3C3C4399;
font-weight: 400;
line-height: 18px;
margin-top: 6px;
margin-bottom: 4px;
}
.bottom-info {
display: flex;
align-items: center;
margin-top: 4px;
column-gap: 4px;
}
.left-section {
display: flex;
align-items: center;
gap: 8px;
}
.avatar-group {
display: flex;
align-items: center;
}
.avatar {
width: 20px;
height: 20px;
border-radius: 50%;
background: #e0e0e0;
border: 2px solid #ffffff;
margin-left: -8px;
overflow: hidden;
box-sizing: border-box;
.avatar-image {
width: 100%;
height: 100%;
object-fit: cover;
}
&:first-child {
margin-left: 0;
z-index: 3;
}
&:nth-child(2) {
z-index: 2;
}
&:nth-child(3) {
z-index: 1;
}
}
.registration-text {
font-size: 12px;
color: #999999;
}
.tags {
display: flex;
gap: 4px;
}
.tag {
box-sizing: border-box;
padding: 0 6px;
border: 0.5px solid #00000029;
height: 20px;
border-radius: 20px;
min-width: 38px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #000000;
font-size: 11px;
}
.tag-text-max {
color: #666666;
}
.image-section {
width: 100px;
height: 100px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-basis: 100px;
flex-grow: 0;
flex-shrink: 0;
.image-container {
width: 100%;
height: 100%;
border: 1.5px solid #ffffff;
border-radius: 10px;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
overflow: hidden;
position: absolute;
box-sizing: border-box;
.nut-skeleton,
.nut-skeleton-content,
.nut-skeleton-block {
width: 100%;
height: 100%;
}
.nut-skeleton-block {
margin: 0;
border-radius: unset;
}
.image {
border-radius: 10px;
}
}
}
.single-image {
position: relative;
width: 88px;
height: 88px;
.image-container {
width: 88px;
height: 88px;
transform: rotate(-10deg);
}
}
.double-image {
width: 100%;
height: 100%;
position: relative;
.image-container {
width: 60%;
height: 60%;
position: absolute;
overflow: hidden;
top: 20%;
&:first-child {
z-index: 2;
transform: translateX(4px) rotate(-10deg);
}
&:last-child {
right: 0;
z-index: 1;
transform: translateX(-4px) rotate(10deg);
}
}
}
.triple-image {
width: 100%;
height: 100%;
position: relative;
.image-container {
position: absolute;
overflow: hidden;
&:nth-child(1) {
bottom: 0;
left: 0;
width: 55px;
height: 55px;
z-index: 3;
transform: translateX(4px) rotate(-10deg);
}
&:nth-child(2) {
bottom: 10px;
right: 0;
width: 55px;
height: 55px;
z-index: 2;
transform: rotate(3deg);
}
&:nth-child(3) {
top: 5%;
left: 50%;
width: 100rpx;
height: 100rpx;
z-index: 1;
transform: translateX(-50%);
}
}
}
.image {
width: 100%;
height: 100%;
object-fit: cover;
}

View File

@@ -0,0 +1,57 @@
import { View } from "@tarojs/components";
import { Skeleton } from "@nutui/nutui-react-taro";
import "./index.scss";
const ListCard = () => {
return (
<View className="list-item">
{/* 左侧内容区域 */}
<View className="content">
{/* 标题 */}
<View className="titleWrapper">
<Skeleton visible={false} style={{ width: "180px" }} />
</View>
{/* 时间信息 */}
<View className="date-time">
<Skeleton visible={false} style={{ width: "88px", }} />
</View>
{/* 地点,室内外,距离 */}
<View className="location">
<Skeleton visible={false} style={{ width: "60px", }} />
</View>
{/* 底部信息行:头像组、报名人数、技能等级、比赛类型 */}
<View className="bottom-info">
<View className="left-section">
<View className="avatar-group">
{Array.from({ length: 3 }).map((_, index) => (
<View key={index} className="avatar">
<Skeleton visible={false} style={{ width: "20px", height: '0' }} />
</View>
))}
</View>
</View>
<View className="tags">
<Skeleton visible={false} style={{ width: "64px" }} />
</View>
</View>
</View>
{/* 右侧图片区域 */}
<View className="image-section">
<View className="single-image">
<View className="image-container">
<Skeleton visible={false} />
</View>
</View>
</View>
</View>
);
};
export default ListCard;