用贪吃蛇小游戏的思路手写一个无限循环滚动轮播图

简介: 在某些业务场景下,接入第三方库实现轮播图效果可能并没有那么好用,笔者在接入Swiper插件失败后,还是决定手写一个。那么关于手写轮播图有很多文章已经讲过了,其核心原理是将图片排成一排,设置外层的Div超出隐藏,然后改变定位来实现轮播效果,这样通常不能首尾循环滚动,本文记录了一种对无限循环滚动效果的实现方式。

实现的思路很简单,就是和“贪吃蛇”游戏中蛇身体的移动逻辑一样,每次前进的时候先删除尾部元素,然后再添加到头部,这样无论身体多庞大,始终只有两个元素在改变位置:

image.png

基础效果

有了思路,就不难写出轮播了,这里为了方便使用Vue2创建演示,后面会放上完整Demo及源码,文章只讲思路,就不贴大段代码了,有需要的小伙伴可以先点个收藏~

其中前进还是一样通过改变left来滚动,只是在滚动结束后便立刻修改数据:

// 核心代码
const ulDom = document.getElementsByClassName('ul')[0] // 拿到页面Dom实例
ulDom.style.left = xxx // 控制滚动,注意需要设置transition才有动画

this.images.push(this.images.shift()) // 对轮播列表的数组首尾元素互换

2022-08-15 16.16.25.gif

但是回退就有点不一样了,试想如果此时在第一张图,那么向左跳转的话是没有数据的,也就会产生空白的一片,所以回退做了特殊处理,先把尾部添加到数组前面,同时悄悄地轮播到下一张(去除动画效果),然后才进行回退的操作,等动画结束后pop()把数组末尾删除:

2022-08-15 16.21.21.gif

从页面效果上可能没什么感觉,我们放慢来看看DOM是如何变化的:

2022-08-15 16.01.14.gif

列表虚拟化

可能大家也注意到了,在这个实例中“当前选中”下标是要另外计算的,因为真实的数组下标总是在来回加1减1地改变而已,所以我们可以在此基础上轻松做出一个虚拟列表,做到真正的“无限”滚动。

假设轮播数组足够大,且页面结构又繁多复杂情况下,直接渲染轮播会产生很多DOM结构,这将导致页面性能下降,下面放上完整在线代码演示,你可以修改“列表总数”为9999,然后关闭虚拟列表开关,此时你可能会卡到根本点不动轮播:

代码片段

一般来说可能不会有大量轮播图的场景,笔者的业务需求是在数据大屏中展示海报视频等轮播,而数据量是没有上限的,就可能会出现大量轮播数据的请求。

此时根据“展示个数”动态的修改实际渲染的DOM个数,无论来多少张轮播都不会影响到性能了,利用Vue的计算属性可以很轻松地做到:

computed: {
    realImages() {
      return this.images.slice(0, Number(this.slidesPerView) + 2)
      // this.slidesPerView 即为展示个数,轮播图实际渲染个数总长度只会比展示个数多两个
    },
  },

图片加载闪动

这是后续的一个优化点,由于数据截取的原因,我会一直改变渲染的数组,在页面中的表现为图片突然更换了地址,如果该元素节点存在上一张图片,则会产生闪动:

如下图,可以看到我停留在第10张时啥也没做,但由于新的图片url其实还在加载,等到加载完了显示出来,图片突然闪动变化,体验就非常怪。

2022-08-15 16.54.40.gif

于是我重新写了一个图片容器组件来代替img标签,组件在img上层覆盖上一个loading遮罩,利用img标签的onLoad事件来判断图片加载完成,再隐藏loading,每次src改变的时候就重新出现loading,代码实现非常简单:

<template>
  <div class="img__box">
    <div v-show="loading" class="load"></div>
    <img v-show="!loading" :src="src" @load="loadDone" />
  </div>
</template>

<script>
export default {
  props: {
    src: {},
  },
  data() {
    return {
      loading: false,
    }
  },
  watch: {
    src() {
      this.loading = true
    },
  },
  methods: {
    loadDone() {
      this.loading = false
    },
  },
}
</script>

<style scoped>
.img__box {
  position: relative;
  overflow: hidden;
}
.img__box > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.load {
  position: absolute;
  width: 100%;
  height: 100%;
}
.load::after {
  position: absolute;
  content: '';
  top: 50%;
  left: 50%;
  width: 30px;
  margin-left: -15px;
  height: 30px;
  margin-top: -15px;
  border: 2px solid rgba(255, 255, 255, 0.7);
  border-top-color: transparent;
  border-radius: 100%;
  animation: circle infinite 0.75s linear;
}

@keyframes circle {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}
</style>

这样把轮播的img标签直接替换为这个组件就解决问题了:

2022-08-15 17.01.03.gif

最后附上:完整的Demo源码

相关文章
|
数据库
mongo占用内存过大解决方案
自己有一个测试用的服务器,配置很低。年前出现几次问题,重启后就好了也就没注意。后来越来越频繁就调查了一下,发现重启后内存就一直增长直到接近100%。使用ps aux查看cpu和内存使用情况,发现mongo占用了大部分的内存,这是什么情况?
1051 0
|
10月前
|
IDE Shell 开发工具
灵码使用体验
上周使用了通义灵码三天,分享一下体验。相较于Trae、VSCode和CodeBuddy,灵码存在一些不足:响应速度较慢,生成代码效率低;汉化不够完善,菜单仍为英文;纠错能力弱,无法有效提示代码问题;Shell集成效果差,终端命令错误处理不佳;MCP工具集成不如Trae便捷。不过,灵码也有亮点:支持超长上下文输入,有助于精确开发;Qwen3推理能力强,能较好理解用户意图并编辑代码。希望后续更新能优化这些问题,提升用户体验。
2184 0
|
机器学习/深度学习 人工智能 运维
智能运维:未来之路的探索与实践
在数字化浪潮中,智能运维如同航船之舵,引领企业乘风破浪。本文将深入探讨智能运维的发展趋势,从自动化到智能化的转变,以及人工智能、大数据等技术如何赋能传统运维,提升效率与价值。我们将一同见证智能运维如何重塑IT服务管理的未来。
|
机器学习/深度学习 监控 自动驾驶
卷积神经网络有什么应用场景
【10月更文挑战第23天】卷积神经网络有什么应用场景
2453 2
|
项目管理
推荐5款好用靠谱的工时管理工具
在快节奏的工作环境中,精准的工时记录与高效的项目管理至关重要。本文推荐五款工时管理软件:Trello界面简洁但功能较简单;Worktile功能丰富但操作复杂;Clockify专注工时追踪与报告生成;Asana功能全面但价格昂贵;板栗看板简洁高效,易于上手,特别适合预算有限的团队。选择合适的工具,提升团队效率。
|
存储 SQL 测试技术
基于SpringBoot+Vue入校申报审批系统的设计与实现(源码+部署说明+演示视频+源码介绍+lw)(2)
基于SpringBoot+Vue入校申报审批系统的设计与实现(源码+部署说明+演示视频+源码介绍+lw)
425 1
|
自然语言处理 IDE 测试技术
通义灵码VS Code和JetBrains配置指南和使用技巧
通义灵码VS Code和JetBrains配置指南和使用技巧、快捷键操作、功能使用细节说明。
133018 7
|
机器学习/深度学习 人工智能 自然语言处理
利用AI辅助工具提高软件测试效率与准确性
【2月更文挑战第16天】 在快速发展的软件行业中,测试工作是确保产品质量的关键环节。然而,传统的测试方法往往耗时且容易遗漏错误。本文介绍了一种结合人工智能(AI)技术的测试辅助工具,旨在提升软件测试的效率和准确性。通过引入智能化的缺陷预测、自动化测试用例生成以及实时反馈机制,该工具能够显著减少人力资源消耗,同时提高发现潜在问题的能力,为软件测试领域带来革新。
|
前端开发
前端原生 CSS 跑马灯效果,无限轮播(横竖版本,带渐变遮罩,简单实用)
前端原生 CSS 跑马灯效果,无限轮播(横竖版本,带渐变遮罩,简单实用)
594 0
|
Linux 数据库 索引
如何在Linux中进行本地Blast序列比对?
如何在Linux中进行本地Blast序列比对?