引言:产品经理的 “无理要求”🤯
那天下午,产品经理突然拍了拍我的肩膀:“小老弟,咱们这个指标轮播图,每一页都必须放满 4 个,哪怕数据不够也不能空着!空着多难看,影响用户体验!”
我低头看了看接口返回的数据:10 个指标。10 除以 4 等于 2.5,这意味着最后一页只有 2 个指标,剩下两个位置空着,像极了我掉了两颗牙的嘴巴 —— 要多尴尬有多尴尬。
但作为一个专业的前端,我怎么能说 “不行” 呢?我微微一笑:“没问题,包在我身上!”(内心 OS:还好我有摸鱼小技巧💡)
问题场景:轮播图的 “空窗期”😱
先看看我们的原始数据:
const rawItems = [
{ title: "指标 A", blocks: ["a", "b", "c"] },
{ title: "指标 B", blocks: ["a", "b", "c", "d"] },
{ title: "指标 C", blocks: ["a", "b"] },
{ title: "指标 D", blocks: ["a", "b", "c", "d", "e"] },
{ title: "指标 E", blocks: ["a"] },
{ title: "指标 F", blocks: ["a", "b", "c"] },
{ title: "指标 G", blocks: ["a", "b", "c", "d"] },
{ title: "指标 H", blocks: ["a", "b"] },
{ title: "指标 I", blocks: ["a", "b", "c", "d", "e"] },
{ title: "指标 J", blocks: ["a"] },
];
10 个指标,每页放 4 个,正常情况下:
- 第 1 页:A、B、C、D(完美)
- 第 2 页:E、F、G、H(完美)
- 第 3 页:I、J、?、?(空了两个位置!社死现场)
这时候如果直接渲染,最后一页就会像这样:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ 指标 I │ 指标 J │ │ │
│ ● ● ● ● ● │ ● │ │ │
└─────────────┴─────────────┴─────────────┴─────────────┘
产品经理看到肯定会说:“这不行!太丑了!”
解决方案:“循环群演” 大法✨
既然数据不够,那我们就把前面的指标抓过来当 “群演” !反正用户在轮播的时候,也不会太注意是不是重复的,只要页面满满当当,视觉效果好就行!
核心思路:
-
先按每页 4 个把数据切好
-
检查最后一页够不够 4 个
-
如果不够,就从第 1 个指标开始循环,补够 4 个
这里的关键是取模运算(%) ,它能让我们像循环播放背景音乐一样,循环利用前面的数据!
代码解析:手把手教你 “抓群演”👨💻
直接上核心代码:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TDesign Swiper Demo</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/tdesign-vue-next/dist/tdesign.min.css"
/>
<script src="https://unpkg.com/tdesign-vue-next/dist/tdesign.min.js"></script>
<style>
/* 自定义样式以改善整体外观 */
body {
margin: 24px;
background-color: #f6f6f6;
}
#app {
max-width: 1200px;
margin: 0 auto;
padding: 16px;
}
.indicator-item {
background-color: #f6f6f6;
border-radius: 8px;
padding: 16px;
text-align: center;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.indicator-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.indicator-blocks {
display: flex;
gap: 4px;
flex-wrap: wrap;
justify-content: center;
}
.indicator-block {
width: 8px;
height: 8px;
background-color: #0052d9;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="app">
<t-card title="示例轮播" style="height: 300px; padding: 16px">
<t-swiper
:autoplay="true"
:interval="3000"
:loop="true"
:navigation="{type:'fraction'}"
>
<t-swiper-item v-for="(slide, sIdx) in slides" :key="sIdx">
<t-row :gutter="[16, 16]">
<t-col
v-for="(item, idx) in slide"
:key="idx"
:xs="12"
:sm="6"
:md="6"
:lg="3"
:xl="3"
>
<div class="indicator-item">
<div class="indicator-title">{{ item.title }}</div>
<div class="indicator-blocks">
<div
v-for="(block, i) in item.blocks || []"
:key="i"
class="indicator-block"
></div>
<div
v-if="!item.blocks || item.blocks.length === 0"
class="indicator-block"
v-for="i in 3"
:key="'default'+i"
></div>
</div>
</div>
</t-col>
</t-row>
</t-swiper-item>
</t-swiper>
</t-card>
</div>
<script>
const { createApp, computed } = Vue;
const rawItems = [
{ title: "指标 A", blocks: ["a", "b", "c"] },
{ title: "指标 B", blocks: ["a", "b", "c", "d"] },
{ title: "指标 C", blocks: ["a", "b"] },
{ title: "指标 D", blocks: ["a", "b", "c", "d", "e"] },
{ title: "指标 E", blocks: ["a"] },
{ title: "指标 F", blocks: ["a", "b", "c"] },
{ title: "指标 G", blocks: ["a", "b", "c", "d"] },
{ title: "指标 H", blocks: ["a", "b"] },
{ title: "指标 I", blocks: ["a", "b", "c", "d", "e"] },
{ title: "指标 J", blocks: ["a"] },
];
// Vue应用对象定义
const App = {
setup() {
// 每个幻灯片中显示的项目数量
const itemsPerSlide = 4;
const slides = computed(() => {
// 获取原始数据的长度
const n = rawItems.length;
// 如果原始数据为空,则直接返回空数组
if (n === 0) return [];
// 初始化结果数组
const result = [];
// 按照每页itemsPerSlide个项目进行循环处理
// i是每次循环的起始索引,每次递增itemsPerSlide
for (let i = 0; i < n; i += itemsPerSlide) {
// 从rawItems中截取从索引i开始,到i+itemsPerSlide结束的片段
const chunk = rawItems.slice(i, i + itemsPerSlide);
// 检查当前块的长度是否小于每页应该显示的数量
if (chunk.length < itemsPerSlide) {
// 计算还需要多少个项目才能达到每页所需数量
const need = itemsPerSlide - chunk.length;
// 循环添加前几个项目来填充剩余位置
for (let k = 0; k < need; k++) {
// 使用取模运算符来循环利用前面的项目
// 当k超过原始数组长度时,使用k%n来重新从头开始
chunk.push(rawItems[k % n]);
}
}
// 将当前块添加到结果数组中
result.push(chunk);
}
return result;
});
return {
slides,
};
},
};
createApp(App).use(TDesign).mount("#app");
</script>
</body>
</html>
灵魂拷问:k % n 是啥?🤔
这就是我们的 “循环播放键”!
- 当
k=0时,0 % 10 = 0,抓第 1 个指标(A) - 当
k=1时,1 % 10 = 1,抓第 2 个指标(B) - 当
k=10时,10 % 10 = 0,又回到第 1 个指标(A)
就像这样:
原始数据:[A, B, C, D, E, F, G, H, I, J]
最后一页:[I, J]
需要补2个
抓来的群演:A (0%10), B (1%10)
补齐后:[I, J, A, B]
完美!最后一页变成了:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ 指标 I │ 指标 J │ 指标 A │ 指标 B │
│ ● ● ● ● ● │ ● │ ● ● ● │ ● ● ● ● │
└─────────────┴─────────────┴─────────────┴─────────────┘
满满当当,产品经理看了都笑开了花🌸!
效果展示:轮播图的 “完美形态”🎨
现在我们的轮播图:
- 第 1 页:A、B、C、D
- 第 2 页:E、F、G、H
- 第 3 页:I、J、A、B(群演上线!)
用户在轮播的时候,只会觉得 “哇,这个轮播图内容好丰富,每一页都满满的”,根本不会注意到 A 和 B 又出现了一次!
而且我们用了 TDesign 的Swiper组件,配合autoplay和loop,体验丝滑得像德芙巧克力🍫!
总结:摸鱼小技巧,你学会了吗?😏
这个 “循环群演” 大法:
-
简单实用:几行代码就能解决问题
-
视觉效果好:页面满满当当,不再空落落
-
用户体验佳:轮播起来丝滑流畅
-
方便摸鱼:解决了产品经理的需求,你又能多摸 5 分钟鱼了!
以后再遇到数据不够的情况,别慌,试试这个 “循环群演” 大法,让你的前端页面永远 “满满当当”!
最后互动:你们平时遇到数据不够的情况,都是怎么处理的?欢迎在评论区分享你的摸鱼小技巧!👇
如果觉得这篇文章有用,别忘了点赞👍、收藏⭐、转发📤,让更多的前端小伙伴一起快乐摸鱼!