列表骨架屏
This commit is contained in:
0
src/components/GamePlayType/index.module.scss
Normal file
0
src/components/GamePlayType/index.module.scss
Normal file
28
src/components/GamePlayType/index.tsx
Normal file
28
src/components/GamePlayType/index.tsx
Normal 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;
|
||||
@@ -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 {
|
||||
@@ -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;
|
||||
264
src/components/ListCardSkeleton/index.scss
Normal file
264
src/components/ListCardSkeleton/index.scss
Normal 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;
|
||||
}
|
||||
57
src/components/ListCardSkeleton/index.tsx
Normal file
57
src/components/ListCardSkeleton/index.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user