js实现左右轮播图_js 轮播 从右向左-程序员宅基地

技术标签: css  setInterval  JavaScript  js  ajax  

左右版轮播图

js实现左右轮播图,实现效果有自动播放、点击分页器切换和点击左右按钮切换等。

原理

将一些图片在一行中平铺,然后计算偏移量再利用定时器实现定时轮播。

实现效果

  • 多张图片自动轮换展示,对应分页器小圆点高亮显示

  • 图片无缝切换(图片列表中第一张和最后一张图片一致)

  • 鼠标滑入/滑出停止/开启图片轮换展示

  • 点击前进/后退按钮查看当前图片前一张/后一张图片

  • 点击分页器小圆点切换对应图片

实现思路

  • 获取操作对象

  • 请求数据

  • 渲染数据

  • 封装函数autoMove,将其传入定时器,实现图片自动轮换展示

  • 封装函数changeFocus,实现图片对应分页器小圆点高亮显示

  • 绑定鼠标滑入/滑出事件,滑入(滑出)清除(开启)定时器

  • 给左右按钮绑定点击事件

index.js

//获取外层的窗口
let outer = document.getElementById('outer');
//获取图片的容器
let wrapper = document.getElementById('wrapper');
//获取焦点的容器
let list = document.getElementById('list');
let data = null; //用来接收请求的数据
let timer = null;//用来接收定时器的返回值

//1.数据请求
function getData(url) {
    
  let xhr = new XMLHttpRequest;
  xhr.open('get', url, false);
  xhr.onreadystatechange = function () {
    
    if (xhr.readyState === 4 && /^2\d{2}/.test(xhr.status)) {
    
      data = JSON.parse(xhr.responseText);
    }
  }
  xhr.send();
  // console.log(data);
}
getData('banner.json');

//2.数据渲染
function renderHtml() {
    
  let wrapperItems = '';
  let listItems = '';
  data.forEach((item, index) => {
    
    wrapperItems += `<li><img src="${
      item.img}" alt=""></li>`;
    listItems += `<li></li>`;
  });
  //再复制第一张图片放到末尾(让第一张和最后一张一样)
  wrapperItems += `<li><img src="${
      data[0].img}" alt=""></li>`;
  // console.log(wrapperItems);
  //把动态生成的图片插入到页面
  wrapper.innerHTML = wrapperItems;
  //把动态生成的焦点插入到页面
  list.innerHTML = listItems;
}
renderHtml();

//存储当前展示图片的索引
let step = 0;
/*autoMove
图片索引自增(切换下一张图片)
如果当前索引是最后一张图片,将图片列表ul(绝对定位)的left值设置为0,将索引值设为1
一定时间内修改图片列表ul(绝对定位)的left值为 负的每张图片长度*索引(动画)
*/
function autoMove(index) {
    
  step++;
  //如果当前的函数执行的时候index没有值,那就什么都不做,如果index有值,那就把index的值赋值给step即可
  typeof index === 'undefined' ? null : step = index;
  //如果当前的step大于等于5,说明当前已经运动到最后一张图片了,这时候需要马上把wrapper的left值改为0(因为第一张和最后一张一样,所以看不见这个变化)
  //这时候再把step改为1,正常展示第二张
  if (step >= data.length+1) {
    
    wrapper.style.left = 0;
    step = 1;
  }
  changeFocus();
  utils.animate(wrapper, {
     left: -step * 800 }, 500);
}
timer = setInterval(autoMove, 2000);

//用户鼠标滑上outer轮播停止,鼠标离开轮播继续
outer.onmouseover = function () {
    
  clearInterval(timer);
}
outer.onmouseout = function () {
    
  timer = setInterval(autoMove, 2000);
}

let tips = document.querySelectorAll('#list li');//querySelectorAll获取的元素没有映射
//实现焦点跟随
/*changeFocus
如果当前图片索引与分页器索引一致则给当前分页器添加类名active,其他分页器删除类名active(循环)
如果图片索引是最后一张图片,给第一个分页器添加类名active
*/
function changeFocus() {
    
  //切换焦点的显示
  //循环所有的焦点,判断一下当前的step和哪个焦点的索引相等,和谁相等就给谁加上active类名,其余的清除active类名
  for (let i = 0; i < tips.length; i++) {
    
    //tips[i] //每一个焦点 i就是每一个焦点的索引
    if (step === i) {
    
      tips[i].classList.add('active');
    } else {
    
      tips[i].classList.remove('active');
    }
  }
  //如果当前的step是4,说明当前页面显示的是最后一张图片,他和第一张图片共用一个焦点,这时候让第一个焦点高亮就可以了
  if (step === 4) {
    
    tips[0].classList.add('active');
  }
}
//页面初始化的时候执行一次,为了让第一张图片的焦点高亮
changeFocus();

//点击焦点,实现切换对应的图片
function bindClick() {
    
  for (let i = 0; i < tips.length; i++) {
    
    tips[i].onclick = function () {
    
      /* //方式一
      //因为autoMove内部有step++,所以这这里要减一,这样就会跟autoMove内部的step++相互抵消
      step=i-1;
      autoMove(); */

      //方式二
      autoMove(i);
    }
  }
}
bindClick();

//点击小耳朵实现图片切换
right.onclick = function () {
    
  autoMove();
}
//左按钮点击事件
left.onclick = function () {
    
  step -= 2;//图片索引减2(autoMove中索引 会自增)
  if (step == -2) {
    
    //如果索引等于-2,说明现在要显示倒数第二张图片,需要将left设置为负的总图片长度(负的单张图片长度*data.length)
    wrapper.style.left = -data.length * 800 + 'px';
    step = data.length - 2;//索引设置为data.length-2
  }
  autoMove();
}

utils.js

let utils = (function(){
    
    function linear(t,b,c,d){
    
        return c/d*t+b;
    }
 // move
    function animate(curEle,target,duration,callBack){
    
        let begin = {
    };
        let change = {
    };
        for(var key in target){
    
            begin[key] = parseFloat(getComputedStyle(curEle)[key]);
            change[key] =  target[key] - begin[key];
        }
        let interval = 0;
        let timer = setInterval(function(){
    
            interval+=20;
            for(var key in target){
    
                let cur = linear(interval,begin[key],change[key],duration);
                // console.log(interval,begin[key],change[key],duration)
                curEle.style[key] = cur+'px';
            }
            if(interval>=duration){
    
                clearInterval(timer);
                typeof callBack === 'function'? callBack():null
            }
        },20)
    };
    function debounce(fn,wait){
    
        let timer;
        return function(){
    
            clearInterval(timer);
            timer = setTimeout(()=>{
    
                fn.call(this);
            },wait)
        }
    }
    return {
    animate,debounce}
})()

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="index.css">
</head>
<body>
  <div id="outer">
    <!-- 图片 -->
    <ul id="wrapper">
      <li><img src="img/banner1.jpg" alt=""></li>
      <!-- <li><img src="img/banner2.jpg" alt=""></li>
      <li><img src="img/banner3.jpg" alt=""></li> -->
    </ul>
    <!-- 焦点 -->
    <ul id="list">
      <li class="active"></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
    <!--  -->
    <a href="javascript:;" id="left"> < </a>
    <a href="javascript:;" id="right"> > </a>
  </div>

  <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.3.min.js"></script>
  <script src="utils.js"></script>
  <script src="index.js"></script>
</body>
</html>

index.css

*{
    
    margin: 0;
    padding: 0;
}
#outer{
    
    width: 800px;
    height: 300px;
    margin: 100px auto;
    border: 1px solid red;
    overflow: hidden;
    position: relative;
    cursor: pointer;
}
#wrapper{
    
    display: flex;
    /* width: 2400px; */
    height: 300px;
    background: orangered;
    position: absolute;
    left: 0;
    list-style: none;
}
#wrapper li{
    
    width: 800px;
    height: 300px;
}
#wrapper li img{
    
    display: block;
    width: 100%;
    height: 100%;
}
/* -------------------------- */
#list{
    
    /* width: 250px; */
    height: 30px;
    /* background: palevioletred; */
    position: absolute;
    left: 50%;
    list-style: none;
    display: flex;
    /* justify-content: space-around; */
    align-items: center;
    transform: translate(-50%,0);
    bottom: 10px;
}
#list li{
    
    width: 25px;
    height: 25px;
    margin: 0 5px;
    border-radius: 50%;
    background: rgba(0, 0, 0, .5);
}
#list li.active{
    
    background: orangered;
}
/* ------------------------------ */
#outer a{
    
    width: 30px;
    height: 50px;
    text-align: center;
    line-height: 50px;
    background: rgba(0,0,0,.5);
    position: absolute;
    top: 50%;
    text-decoration: none;
    color: #fff;
}
#left{
    
    left: 0;
}
#right{
    
    right: 0;
}

banner.json

[
  {
    
    "id": 1,
    "img": "img/banner1.jpg",
    "desc": "广阔的就业推荐机会",
    "link": "http://www.zhufengpeixun.cn/"
  },
  {
    
    "id": 2,
    "img": "img/banner2.jpg",
    "desc": "梦想起飞从选择珠峰培训开始",
    "link": "http://www.zhufengpeixun.cn/"
  },
  {
    
    "id": 3,
    "img": "img/banner3.jpg",
    "desc": "把握未来,掌握先机",
    "link": "http://www.zhufengpeixun.cn/"
  },
  {
    
    "id": 4,
    "img": "img/banner4.jpg",
    "desc": "先学习,后交费,学不好,不收费",
    "link": "http://www.zhufengpeixun.cn/"
  }
]
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_44419617/article/details/111402332

智能推荐

Android中/system/build.prop文件解读_op system/system/build.prop cp: error writing 'sys-程序员宅基地

文章浏览阅读3k次。在/system下的build.prop文件里,我们常看见以下语句。ro.ril.hsdpa.category = 10ro.ril.hsupa.category = 6ro.ril.hsxpa = 2ro.ril.enable.amr.wideband=1wifi.supplicant_scan_interval=45dalvik.vm.heapsize=24m _op system/system/build.prop cp: error writing 'system/system/build.prop': no

怪异的inet_ntoa函数---C/C++返回内部静态成员的陷阱_inet_ntoa 释放-程序员宅基地

文章浏览阅读600次。在我们用C/C++开 发的过程中,总是有一个问题会给我们带来苦恼。这个问题就是函数内和函数外代码需要通过一块内存来交互(比如,函数返回字符串),这个问题困扰和很多开发 人员。如果你的内存是在函数内栈上分配的,那么这个内存会随着函数的返回而被弹栈释放,所以,你一定要返回一块函数外部还有效的内存。这 是一个让无数人困扰的问题。如果你一不小心,你就很有可能在这个上面犯错误。当然目前有很多解决_inet_ntoa 释放

ZwQuerySystemInformation 查看系统进程信息_zwduplicateobject系统进程-程序员宅基地

文章浏览阅读580次。#include typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, Syst_zwduplicateobject系统进程

深入理解Java虚拟机-第3章-垃圾收集器_从整体来看是基于“标记--整理”算法实现的收集器;从局部上来看是基于“复制”-程序员宅基地

文章浏览阅读118次。JVM的垃圾收集器经历了多代的发展,从单线程收集器到多线程收集器。一、背景垃圾回收器经历过多代的发展,从单线程到多线程,垃圾收集器的大家族产品如下,每一个连线表示可以组合使用。接下来大概分为几个阶段详细介绍下各个垃圾回收器的特点:阶段收集器名称区域并行/串行/并发算法优缺点适用场景第一阶段Serial新生代串行复制响应速度快单CPU环境下的Client模式Serial Old老年代串行标志-整理响应速度快单CPU环境下的Client._从整体来看是基于“标记--整理”算法实现的收集器;从局部上来看是基于“复制”

反弹shell-程序员宅基地

文章浏览阅读1.7w次,点赞19次,收藏92次。一、课时目标1.理解shell的概念2.理解交互式shell和非交互式shell的区别3.掌握反弹shell的原理和方法_反弹shell

做crud遇到的问题_this.crud.toquery()-程序员宅基地

文章浏览阅读363次。1.crud的流程1 流程: servlet调service进行业务处理service调dao完成数据库操作dao在把数据库操作结果在给serviceservice继续处理在把结果返回给servletservlet在根据service的处理结果选择是请求转发还是重定向来显示页面2.登录功能效验实现2 流程(登录功能效验实现):servlet层中UserServlet调UserServiceImplUserServiceImpl调UserDaoImplUserDaoImpl操作数据_this.crud.toquery()

随便推点

C++ vector用法总结_vector<int>::iterator it = m_vec.begin()-程序员宅基地

文章浏览阅读394次,点赞2次,收藏3次。C++ 向量 vector 是一种对象实体, 能够容纳许多其他类型相同的元素, 因此又被称为容器。 与string相同, vector 同属于STL(Standard Template Library, 标准模板库)中的一种自定义的数据类型, 可以广义上认为是数组的增强版。_vector::iterator it = m_vec.begin()

Java学习路线&笔记链接_java 学习连-程序员宅基地

文章浏览阅读195次。Java学习路线&笔记链接????JAVASE数据库mysql(或oracle)JDBCWEB前端HTMLCSSJavaScriptJavaWeb(web后端)ServletJSPweb进阶AJAXjQueryJavaWeb项目实战SSM三大框架(额外可选学SSH)MyBatisSpringSpringMVC互联网分布式JAVASEJava语言的基础,是Java的最基本的库。基础语法加常用类库。数据库mysql(或oracle)数据库是所有程序员都需要学习的,因为不管是C语言,还是C++,_java 学习连

ESD二极管ESD05V56T-2L参数_esd二极管容值-程序员宅基地

文章浏览阅读358次。      ESD05V56T-2L的参数:  封装:SOT-563  电压:5V  钳位电压:9.8V  容值:3pF  功率:100W  ESD05V56T-2L的特性:  1、依据(tp=8/20μs)线路,峰值脉冲功率为100W  2、保护两个I/O线及电源线  3、适合高速接口的低电容  4、工作电压:5V  5、超小型封装要求小于2.9mm2的PCB面积  6、IEEE1394高速火线端口  6、IEC61000-4-2(ESD)±15_esd二极管容值

vim 配置-程序员宅基地

文章浏览阅读381次。1.安装git:sudoapt-get install git2.安装Bundle:gitclone https://github.com/gmarik/vundle.git~/.vim/bundle/vundle3.在.vimrc文件中添加如下语句4.自动安装插件wget -qO- https://raw.github.com/ma6174/vim/master/setup.sh | sh..._bundle 'last_edit_marker.vim

重生-程序员宅基地

文章浏览阅读479次。【内容】在提高班什么才是最有价值的? 在跟一些同学聊天的过程中,很多同学说不会干太长时间的计算机的,也包括最近在读的李笑来老师的重生-七年就是一辈子,每七年就会获得一项新的技能,包括Bill经常给我们分享的内容,还有自己进提高班的初衷,让我更加深刻地意识到,提高班根本不是单纯地学习计算机知识的地方,大家想想,像现在知识爆棚的时代,每半年就有1/2的知识被淘汰,如果我们以学习知识为目的,那无疑我们是

Extjs GridPanel用法详解_<ext:gridpanel-程序员宅基地

文章浏览阅读4.1k次。Extjs GridPanel 提供了非常强大数据表格功能,在GridPanel可以展示数据列表,可以对数据列表进行选择、编辑等。创建GridPanel要使用GridPanel,首先要定义Store,而在创建Store的时候必须要有Model,因此我们首先来定义Model://1.定义ModelExt.define("MyApp.model.User", { extend: "Ext.d..._