组件 · COMPONENT
骨架屏 Skeleton
纸灰底块,一道微光 1.4 秒扫过。取代「LOADING…」文字。卡片不另写骨架——同一个组件传 loading,骨架与真实态共用同一段布局。
import { Skel } from './components/v4/Skeleton.jsx'
export function Lines() {
return (
<div style={{ width: 420, maxWidth: '100%', display: 'flex', flexDirection: 'column', gap: 8 }}>
<Skel w="62%" h={14} />
<Skel w="92%" h={11} />
<Skel w="78%" h={11} />
</div>
)
}<div style="width: 420px; max-width: 100%; display: flex; flex-direction: column; gap: 8px">
<div class="zzm-skel" style="width: 62%; height: 14px; border-radius: 8px"></div>
<div class="zzm-skel" style="width: 92%; height: 11px; border-radius: 8px"></div>
<div class="zzm-skel" style="width: 78%; height: 11px; border-radius: 8px"></div>
</div>/* base.css */
.zzm-v4 .zzm-skel {
position: relative;
overflow: hidden;
background: #EFEFEC;
border-radius: 8px;
}
.zzm-v4 .zzm-skel::after {
content: '';
position: absolute;
inset: 0;
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .65), transparent);
animation: zzmShimmer 1.4s ease infinite;
}
/* keyframes */
@keyframes zzmShimmer { 100% { transform: translateX(100%) } }| 属性 | 取值 | 默认 | 说明 |
|---|---|---|---|
| w | number · string | '100%' | 宽:数字为 px,也可写百分比 |
| h | number · string | 12 | 高 |
| r | number | 8 | 圆角(取圆角梯) |
| style | object | — | 并入,常用于 marginTop |
卡片自带骨架
课程卡、系列卡、课节卡都接受 loading:在同一段 JSX 里把数据位换成 Skel。改真卡的内距或字号,骨架自动跟着变——能消失的分支比能写对的分支好。
import { CourseCard } from './components/v4/CourseCard.jsx'
import { SeriesCard } from './screens/v4/course/SeriesCard.jsx'
import { LessonCard } from './screens/v4/course/LessonCard.jsx'
export function CardSkeletons() {
return (
<>
<CourseCard loading />
<SeriesCard loading />
<LessonCard loading />
</>
)
}<div
style="
border: 1px solid rgba(0, 0, 0, 0.09);
border-radius: 16px;
background: #ffffff;
overflow: hidden;
"
>
<div style="aspect-ratio: 16/9; background: #131316; position: relative; overflow: hidden"></div>
<div style="padding: 16px 18px 17px">
<div class="zzm-skel" style="width: 62%; height: 16px; border-radius: 8px"></div>
<div
class="zzm-skel"
style="width: 92%; height: 13px; border-radius: 8px; margin-top: 6px"
></div>
<div
class="zzm-skel"
style="width: 40%; height: 11.5px; border-radius: 8px; margin-top: 10px"
></div>
<div style="margin-top: 13px; display: flex; align-items: center; gap: 8px">
<div class="zzm-skel" style="width: 86px; height: 10.5px; border-radius: 8px"></div>
<span style="flex: 1"></span>
<div class="zzm-skel" style="width: 58px; height: 12px; border-radius: 8px"></div>
</div>
</div>
</div>
<div
style="
border-radius: 16px;
background: #ffffff;
overflow: hidden;
border: 1px solid rgba(0, 0, 0, 0.09);
"
>
<div style="aspect-ratio: 16/9; background: #131316; position: relative; overflow: hidden"></div>
<div style="padding: 15px 17px 16px">
<div class="zzm-skel" style="width: 58%; height: 16px; border-radius: 8px"></div>
<div
class="zzm-skel"
style="width: 94%; height: 12.5px; border-radius: 8px; margin-top: 5px"
></div>
<div
class="zzm-skel"
style="width: 70%; height: 12.5px; border-radius: 8px; margin-top: 5px"
></div>
<div
class="zzm-skel"
style="width: 150px; height: 10.5px; border-radius: 8px; margin-top: 10px"
></div>
<div style="margin-top: 12px; display: flex; flex-wrap: wrap; gap: 4px">
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
<div class="zzm-skel" style="width: 16px; height: 16px; border-radius: 4px"></div>
</div>
<div
class="zzm-skel"
style="width: 60px; height: 10px; border-radius: 8px; margin-top: 7px"
></div>
</div>
</div>
<div class="zzm-cardlink">
<div style="aspect-ratio: 16/9; border-radius: 12px; background: #131316; overflow: hidden"></div>
<div style="margin: 11px 2px 3px">
<div class="zzm-skel" style="width: 72%; height: 14px; border-radius: 8px"></div>
</div>
<div style="margin: 0 2px">
<div class="zzm-skel" style="width: 48%; height: 12.5px; border-radius: 8px"></div>
</div>
</div>/* base.css */
.zzm-v4 .zzm-skel {
position: relative;
overflow: hidden;
background: #EFEFEC;
border-radius: 8px;
}
.zzm-v4 .zzm-skel::after {
content: '';
position: absolute;
inset: 0;
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .65), transparent);
animation: zzmShimmer 1.4s ease infinite;
}
/* controls.css */
.zzm-v4 .zzm-cardlink {
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, .09);
border-radius: 16px;
padding: 12px;
cursor: pointer;
box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.zzm-v4 .zzm-cardlink:hover {
transform: translateY(-3px);
border-color: rgba(0, 0, 0, .3);
box-shadow: 0 10px 30px rgba(0, 0, 0, .09), 0 1px 2px rgba(0, 0, 0, .04);
}
/* keyframes */
@keyframes zzmShimmer { 100% { transform: translateX(100%) } }铁律
✓ 要骨架与真实态同源(loading prop)
✗ 不要单独手写一份「看起来差不多」的骨架组件
✗ 不要用「加载中…」文字或转圈占位整块内容