简易实现无缝切换自动轮播

news2024/11/15 13:57:14

原理

  • 页面中设置一个父盒子 bannerBox,固定宽高,相当于一个窗口,超出部分隐藏
  • bannerBox 内部设置一个图片盒子 imgBox,横向(或纵向)依次排列图片
  • 添加定时器,每隔一段时间,imgBox 向左(或向上)移动一段距离
  • 为移动的过程添加 transition 过渡效果

在这里插入图片描述

  • 如上图所示,一共 4 张图,每张宽度设置为 600px,imgBox 宽度设置为 4*600 = 2400px,使得 4 张图片恰好可以在 imgBox 内横向排开。bannerBox 宽度为 600px,溢出部分隐藏,每隔 2 秒,imgBox 向左移动 600px。

初步实现

DOM 结构搭建

  • 设置 bannerBox、imgBox、img 的相关属性
<div class="bannerBox">
  <div
    class="imgBox clearfix"
    :style="{
      width: imgList.length * 600 + 'px',
    }"
  >
    <div class="sinImg" v-for="(item, index) in imgList" :key="index">
      <img :src="item" alt="" />
    </div>
  </div>
</div>
data() {
 return {
    banner1: require("@I/banner1.jpg"),
    banner2: require("@I/banner2.jpg"),
    banner3: require("@I/banner3.jpg"),
    banner4: require("@I/banner4.jpg"),
    imgList: [], // 轮播展示图片
    activeIndex: 0,
  };
},
mounted() {
  this.getImgList();
},
methods: {
  getImgList() {
    this.imgList = [ this.banner1, this.banner2, this.banner3, this.banner4 ];
  },
}
.bannerBox {
 width: 600px;
 overflow: hidden;
 border-radius: 16px;
 .imgBox {
   transform: translateX(0);
   .sinImg {
     float: left;
     img {
       width: 600px;
     }
   }
 }
}
  • imgBox 盒子范围
    在这里插入图片描述
  • 第二张图片位置
    在这里插入图片描述

添加定时器

<div class="bannerBox">
  <div
    class="imgBox clearfix"
    :style="{
      width: imgList.length * 600 + 'px',
      transform: transform,
      transition: transition,
    }"
  >
    <div class="sinImg" v-for="(item, index) in imgList" :key="index">
      <img :src="item" alt="" />
    </div>
  </div>
</div>
data() {
 return {
    banner1: require("@I/banner1.jpg"),
    banner2: require("@I/banner2.jpg"),
    banner3: require("@I/banner3.jpg"),
    banner4: require("@I/banner4.jpg"),
    imgList: [], // 轮播展示图片
    activeIndex: 0,
    timmer: null,
    transition: "transform 1s ease-in-out",
    transform: "translateX(0px)",
  };
},
mounted() {
  this.getImgList();
},
methods: {
  getImgList() {
    this.imgList = [ this.banner1, this.banner2, this.banner3, this.banner4 ];
    this.bannerFunc();
  },
}
// 自动轮播
bannerFunc() {
  this.timmer = setInterval(() => {
    // 开启轮播,自动向右
    // 标识索引加一
    this.activeIndex += 1;
    // 判断如果到了最后一张
    if (this.activeIndex > this.imgList.length - 1) {
      // 索引重置
      this.activeIndex = 0;
    }
    // 图片盒子向左移动,当前索引 * 盒子宽度
    this.transform = "translateX(" + this.activeIndex * -600 + "px)";
  }, 2000);
},
  • 上述方法在轮播图播放到最后一张 banner4 时,索引重置,会显示第一张图片 banner1,但是由于有 transition 过渡属性。视觉上的效果是,轮播图播放到 banner4 时,在 1s 的时间内,imgBox 向右移动(与轮播自动播放方向相反),快速依次略过 banner3banner2,到达 banner1

在这里插入图片描述

优化无缝衔接

  • 为了优化视觉效果,在图片数组最后添加一张 banner1,轮播图到达最后一张(banner1)时,关闭 transition 过渡属性,并且瞬间移动到数组第一张(banner1),开启新一轮的轮播
  • setInterval 定时器内部添加 setTimeout 定时器,用延时来模拟 transition 的 1s 过渡
 getImgList() {
  this.imgList = [ this.banner1, this.banner2, this.banner3, this.banner4, this.banner1 ];
  this.bannerFunc();
},
// 自动轮播
bannerFunc() {
  this.consoleTimeStr("开始调用 bannerFunc 方法", "red");
  this.timmer = setInterval(() => {
    // 开启轮播,自动向右
    this.consoleTimeStr("开始调用 toNext 方法", "blue");
    // 标识索引加一
    this.activeIndex += 1;
    // 图片盒子向左移动,当前索引 * 盒子宽度
    this.transform = "translateX(" + this.activeIndex * -600 + "px)";
    // 开启过渡效果
    this.transition = "transform 1s ease-in-out";
    // 判断如果到了最后一张(展示的是 banner1)
    if (this.activeIndex == this.imgList.length - 1) {
      // 索引重置,最后一张的 banner1 偷偷换成第一张的 banner1
      this.activeIndex = 0;
      // 在当前 interval 定时器内部,添加 timeOut 定时器
      // 关闭过渡效果,将当前图片盒子“瞬移”到初始位置
      this.consoleTimeStr("无缝衔接准备~", "yellowgreen");
      setTimeout(() => {
        this.transform = "translateX(" + this.activeIndex * -600 + "px)";
        this.transition = "none";
        this.consoleTimeStr("偷偷切换回去了!", "green");
      }, 1000);
    }
  }, 2000);
},
// 打印方法
consoleTimeStr(flag, color) {
  let time = new Date();
  let minute = time.getMinutes();
  let second = time.getSeconds();
  if (minute < 10) {
    minute = "0" + minute;
  }
  if (second < 10) {
    second = "0" + second;
  }
  let str = minute + ":" + second;
  console.log("%c" + flag + ",当前时间:" + str, "color: " + color + ";");
},

在这里插入图片描述

  • 上述打印语句可以看出,在 26:48 时,开启了 1s 的 setTimeout 定时器
  • 在这 1s 内,关闭了 transition 过渡效果,将 imgBox 位移恢复到初始位置,可以看做是瞬间位移
  • 这样做就解决了上一步骤向相反方快速移动的效果

左右切换按钮

  • 轮播可添加左右切换按钮
  • 自动切换的效果可封装为右切换效果

完整代码

<template>
  <div class="page">
    <div class="bannerBox">
      <div
        class="imgBox clearfix"
        :style="{
          width: imgList.length * 600 + 'px',
          transform: transform,
          transition: transition,
        }"
      >
        <div class="sinImg" v-for="(item, index) in imgList" :key="index">
          <img :src="item" alt="" />
        </div>
      </div>
    </div>
    <div class="dotBox clearfix">
      <div :class="{ active: activeIndex == 1 }"></div>
      <div :class="{ active: activeIndex == 2 }"></div>
      <div :class="{ active: activeIndex == 3 }"></div>
      <div :class="{ active: activeIndex == 4 }"></div>
    </div>
    <div class="btnBox">
      <div class="left" @click="toPrev('clear')">&lt;</div>
      <div class="right" @click="toNext('clear')">&gt;</div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      banner1: require("@I/banner1.jpg"),
      banner2: require("@I/banner2.jpg"),
      banner3: require("@I/banner3.jpg"),
      banner4: require("@I/banner4.jpg"),
      imgList: [], // 轮播展示图片
      activeIndex: 1,
      timmer: null,
      transition: "transform 1s ease-in-out",
      transform: "translateX(-600px)",
    };
  },
  mounted() {
    this.getImgList();
  },
  methods: {
    getImgList() {
      // 轮播数组,在第一个和最后一个补位
      this.imgList = [
        this.banner4,
        this.banner1,
        this.banner2,
        this.banner3,
        this.banner4,
        this.banner1,
      ];
      this.bannerFunc();
    },
    // 自动轮播
    bannerFunc() {
      this.consoleTimeStr("开始调用 bannerFunc 方法", "red");
      this.timmer = setInterval(() => {
        // 开启轮播,自动向右
        this.toNext();
      }, 2000);
    },
    // 切换到上一张图
    toPrev() {
      this.consoleTimeStr("开始调用 toPrev 方法", "blue");
      // 标识索引减一
      this.activeIndex -= 1;
      // 图片盒子向右移动,当前索引 * 盒子宽度
      this.transform = "translateX(" + this.activeIndex * -600 + "px)";
      // 开启过渡效果
      this.transition = "transform 1s ease-in-out";
      // 判断如果到了第一张(展示的是 banner4)
      if (this.activeIndex == 0) {
        // 索引重置,第一张的 banner4 偷偷换成倒数第二张的 banner4
        this.activeIndex = this.imgList.length - 2;
        // 在当前 interval 定时器内部,添加 timeOut 定时器
        // 关闭过渡效果,将当前图片盒子“瞬移”到初始位置
        this.consoleTimeStr("无缝衔接准备~", "yellowgreen");
        setTimeout(() => {
          this.transform = "translateX(" + this.activeIndex * -600 + "px)";
          this.transition = "none";
          this.consoleTimeStr("偷偷切换回去了!", "green");
        }, 1000);
      }
      console.log("activeIndex", this.activeIndex, "transform", this.transform);
    },
    // 切换到下一张图
    toNext() {
      this.consoleTimeStr("开始调用 toNext 方法", "blue");
      // 标识索引加一
      this.activeIndex += 1;
      // 图片盒子向左移动,当前索引 * 盒子宽度
      this.transform = "translateX(" + this.activeIndex * -600 + "px)";
      // 开启过渡效果
      this.transition = "transform 1s ease-in-out";
      // 判断如果到了最后一张(展示的是 banner1)
      if (this.activeIndex == this.imgList.length - 1) {
        // 索引重置,最后一张的 banner1 偷偷换成第二张的 banner1
        this.activeIndex = 1;
        // 在当前 interval 定时器内部,添加 timeOut 定时器
        // 关闭过渡效果,将当前图片盒子“瞬移”到初始位置
        this.consoleTimeStr("无缝衔接准备~", "yellowgreen");
        setTimeout(() => {
          this.transform = "translateX(" + this.activeIndex * -600 + "px)";
          this.transition = "none";
          this.consoleTimeStr("偷偷切换回去了!", "green");
        }, 1000);
      }
      console.log("activeIndex", this.activeIndex, "transform", this.transform);
    },
    // 打印方法
    consoleTimeStr(flag, color) {
      let time = new Date();
      let minute = time.getMinutes();
      let second = time.getSeconds();
      if (minute < 10) {
        minute = "0" + minute;
      }
      if (second < 10) {
        second = "0" + second;
      }
      let str = minute + ":" + second;
      console.log("%c" + flag + ",当前时间:" + str, "color: " + color + ";");
    },
  },
};
</script>
<style lang="scss" scoped>
.page {
  width: 600px;
  position: relative;
  margin: 20px auto;
  .bannerBox {
    width: 600px;
    overflow: hidden;
    border-radius: 16px;
    .imgBox {
      .sinImg {
        float: left;
        img {
          width: 600px;
        }
      }
    }
  }
  .dotBox {
    width: 70px;
    position: absolute;
    bottom: 10px;
    left: 50%;
    transform: translateX(-50%);
    div {
      float: left;
      width: 10px;
      height: 10px;
      border-radius: 50%;
      margin-right: 10px;
      cursor: pointer;
      background: rgba(255, 255, 255, 0.2);
      &:last-child {
        margin-right: 0;
      }
      &.active {
        background: rgba(255, 255, 255, 0.9);
      }
    }
  }
  .btnBox {
    width: 100%;
    height: 80px;
    line-height: 80px;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    div {
      position: absolute;
      cursor: pointer;
      font-size: 36px;
      color: #fff;
      font-weight: bold;
      font-family: cursive;
    }
    .left {
      left: 10px;
    }
    .right {
      right: 10px;
    }
  }
}
.clearfix:after {
  content: "";
  display: block;
  clear: both;
  visibility: hidden;
}
</style>

未完待续

  • 上述效果暂时未考虑点击左右切换按钮时,停止定时器的效果,后续有时间再补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决使用html标签自定义的按钮点击时有背景底色的问题

问题描述 如下图所示&#xff0c;点击按钮的瞬间&#xff0c;元素底部会出现一个背景色 解决方法 在点击产生背景色的元素的css样式上加上以下代码&#xff1a;-webkit-tap-highlight-color: transparent;

《Unix环境高级编程》/bin/sh: ./fixup.awk: Permission denied

我的代码是从http://www.apuebook.com/code3e.html下载的&#xff0c;先是在 使用cat /etc/redhat-release看到操作系统是CentOS Linux 7.6&#xff0c;使用uname -r看到内核是3.10.0-957.el7.x86_64。 在代码顶级目录下&#xff0c;执行make。 发现报错&#xff1a; ./fi…

软件测试-基础

目录 软件测试的生命周期 如何描述bug 定义bug的级别 bug的生命周期 如何发现更多的bug 软件测试的生命周期 软件测试的生命周期包括: 需求分析->测试计划->测试设计,测试开发->测试执行->测试评估 需求分析:测试人员了解需求,分析需求是否完整,是否正确合…

idea git项目错乱显示多个git项目记录

在项目的.idea文件夹下找到vcs.xml 删除无用的mapping&#xff0c;例如上图&#xff0c;删除…/的目录即可

面试官虐我千百遍,我仍待他如初恋,阿里、腾讯、蚂蚁金服Java技术面试及经验总结

能够进一线互联网公司&#xff0c;是大部分程序员奋斗的目标&#xff0c;有很多小伙伴可能因为学历望而止步&#xff0c;其实只要能力够&#xff0c;学历真的不是那么重要&#xff01; 今天给大家带来ATM(阿里巴巴&#xff0c;腾讯&#xff0c;蚂蚁金服)的Java面试真题&#x…

有效延缓痴呆症:延世大学发现梯度提升机模型能准确预测 BPSD 亚综合征

内容一览&#xff1a;随着人口老龄化程度不断加剧&#xff0c;痴呆症已经成为公共健康问题。目前医学界治疗该病还只能通过药物缓解&#xff0c;尚未发现治愈的有效方法&#xff0c;因此&#xff0c;预防痴呆症尤为紧迫。在这一背景下&#xff0c;延世大学的研究人员开发了多个…

90v转5v芯片

摘要&#xff1a;AH8691内置MOS降压型开关芯片&#xff1a;为电动车控制器供电、通信和太阳能充电设备充电提供解决方案 问&#xff1a;什么是AH8691芯片&#xff1f; 答&#xff1a;AH8691是一款内置MOS降压型开关芯片&#xff0c;可将输入电压范围从10V至100V降压转换为稳定…

软件测试必备7大技能

一、测试用例的编写 1.在测试中最重要的文档&#xff0c;他是测试工作的核心&#xff0c;是一组在测试时输入输出的标准&#xff0c;是软件需求的具体对照。编写测试用例&#xff0c;是测试人员的基本功&#xff0c;真正能写好的人并不多。 2.测试用例包含的内容&#xff1a;…

互联网医院牌照申请流程|互联网医院审批流程

​随着科技的不断进步和社会的发展&#xff0c;互联网医院已经成为了当前的热点。而互联网医院的准入门槛自然也就越来越高。如果您计划成立一个互联网医院&#xff0c;您需要了解申请互联网医院牌照所需要注意的方面以及申请的流程。 一、资质申请前的准备 1、立项阶段准备 …

Python实现ACO蚁群优化算法优化LightGBM分类模型(LGBMClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

拍卖房变卖什么意思

法拍房的起拍价一般是评估价的七折。但是有一种法拍房比较特殊&#xff0c;起拍价接近评估价的五折&#xff0c;而且竞争力度很小&#xff0c;基本都是以低价成交的。它&#xff0c;就是处于变卖阶段的法拍房。那么拍卖房变卖什么意思? 一、拍卖房变卖什么意思  人民法院对查…

Linux之快捷键使用

目录 Linux之快捷键使用 histot 定义 用法 选项及作用 参数 断开长命令行 在一行输入多个命令 快捷方式 引用上一条命令的最后一个参数 --- !$ 实现生产环境中&#xff0c;history命令记录操作时间、操作用户、操作IP 1./etc/profile文件中加入以下内容 2.执行 source…

数字孪生是智慧城市管理的新引擎

数字孪生是一种创新的技术和概念&#xff0c;随着技术成熟逐渐为智慧城市管理带来深远的影响。数字孪生将物理世界与数字世界相结合&#xff0c;通过建立物理实体的数字模型&#xff0c;实现对城市各个方面的实时监测、分析和优化。数字孪生在智慧城市管理中扮演着关键的角色&a…

《Spark篇》------ Spark基础

目录 一、Spark简介 1.1、Spark是什么 1.2、Spark的特点 1.3、Spark生态系统 1.4、Spark Core的组件 1.5、Spark的安装流程 1.5.1、基础环境&#xff0c;安装Linux系统、Java环境和Hadoop环境 1.5.2、下载Spark文件并解压缩 1.5.3、编辑profile 1.5.4、Spark-shell运…

小程序 WEUI 隐藏导航栏使用自定义导航栏时Toptips在顶部显示

使用weui的toptips时候&#xff0c;我们的导航栏使用了自定义&#xff0c;高度根据系统来定的&#xff0c;然后使用form表单验证提示弹窗时&#xff0c;会在最上面被遮挡了。 需要使用weui ext-class 来实现穿透修改样式。 ext-class的top使用继承父元素的top即可 <mp-top…

将数组起始地址定向到SRAM2及错误L6220E的排查

今天有个程序要定义两个大数组&#xff0c;一个32k&#xff0c;一个16k。直接编译的话发现通不过&#xff0c;大概是提示空间不够。因为两个数组就占了48k&#xff0c;可是我的STM32L431CB有64k的RAM&#xff0c;怎么会不够呢&#xff1f;查了资料发现这个芯片的SRAM分为两块&a…

银河麒麟kylin v10 apt deb包问题记录

银河麒麟kylin v10 apt deb包问题记录 https://www.kylinos.cn/support/document/48.html 该补丁支持银河麒麟桌面操作系统V10 2101、V10 0402、V10 0416版本升级到银河麒麟桌面操作系统V10 2107。 下载链接如下 &#xff08;1&#xff09;官网下载链接&#xff1a; AMD64…

Python期末大作业——获取北上广深历史天气并做数据可视化

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 知识点: 动态数据抓包 requests发送请求 结构化非结构化数据解析 一、开发环境: 所使用软件工具&#xff1a; python 3.8 运行代码 pycharm 2022.3.2 辅助敲代码 专业版 需安装第三方模块&#xff1a; requests…

Spring AOP 快速入门

文章目录 一. 什么是Spring AOP二. 为什么要学习Spring AOP三. 学习 Spring AOP3.1 AOP 的组成3.1.1 切面 (Aspect)3.1.2 切点 (Pointcut)3.1.3 通知 (advice)3.1.4 连接点(Joinpoint) 3.2 实现 Spring AOP1. 添加 Spring Boot 的 AOP 框架2. 创建切面3. 创建切点4. 创建通知5.…

vue3自定义指令——元素平滑移动

vue提供一个用户可以高度自定义的指令入口directives 利用这个入口我们实现一个常见的元素平滑移动的自定义指令 ‘sl’ 首先我们结合指令创建一个多元素的界面&#xff1a; 这个场景我们在很多网站&#xff0c;商城都有见过&#xff0c;特别对于移动端的清单类界面 我们的终极…