需求与分析

需求:
循环无缝自动轮播五张图,按左右箭头可以手动切换图片,鼠标点击轮播图下面按钮 1 2 3 4 5会跳转到对应的第1 2 3 4 5张图片。鼠标放到轮播图的图片上时不再自动轮播并且左右箭头显示出来,鼠标移开时左右箭头隐藏掉并且自动轮播。

效果图:


分析:

布局:准备七张图片实现所谓的无缝轮播,固定七张图片的宽高,下面假设为600px*400px。假设html分为三个区:图片区、按钮区、箭头区。然后用个div包住这三个区并且固定该div的宽高也为600*400。

样式:左右居中、距离页面顶部100px显示。五个按钮为圆形的,并且轮播到哪张图或者点到哪个按钮时,该按钮颜色变化。其余的小样式具体写代码的时候佛系添加。

JS脚本:就说明一点图的摆放位置,其余写到那部分代码的时候再说。

七张图中,有两张是和那不同的五张图片中的第一张、第五张相同的。其中和五张不同图中和第一张相同的图放置在七张图片中第七张,和五张不同图中和第五张相同的图放置在七张图片中第一张。原因写到那部分代码时会再说

实现步骤

1、先来个html框架

<body>
<div class="container">
<div class="wrap">
<img src="./imgs/5.jpg" alt="5">
<img src="./imgs/1.jpg" alt="1">
<img src="./imgs/2.jpg" alt="2">
<img src="./imgs/3.jpg" alt="3">
<img src="./imgs/4.jpg" alt="4">
<img src="./imgs/5.jpg" alt="5">
<img src="./imgs/1.jpg" alt="1">
</div>
<div class="button">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
</div>
<a href="javascript:void(0);" class="jt jt_left">&lt;</a>
<a href="javascript:void(0);" class="jt jt_right">&gt;</a>
</div>

给a标签加 javascript:void (0);是为了不让a标签跳转。

2、定义样式

主要目的:给总div、图片区按钮区div、图片、按钮、左右箭头定义宽高,让七个图片并排显示,五个按钮位于图片底部居中显示,两个箭头分别到左右两边的适中位置显示。

/* 清除默认样式 */
*{
margin: 0;
padding: 0;
text-decoration: none;
}
/* 总div */
div.container{
position: relative;
width: 600px;
height: 400px;
margin: 100px auto 0 auto;
box-shadow: 0 0 5px aqua;
overflow: hidden;
}
/* 图片区 */
div.container div.wrap{
position: absolute;
width: 4200px;
height: 400px;
z-index: 1;
} div.container div.wrap img{
width: 600px;
height: 400px;
float: left;
}
/* 按钮区 */
div.container div.button{
position: absolute;
right: 225px;
bottom: 15px;
width: 150px;
height: 20px;
z-index: 2;
text-align: center;
} div.container div.button span{
margin-left: 5px;
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: greenyellow;
text-align: center;
color: white;
cursor: pointer;
opacity: 0.6;
}
/* 轮播到哪张图,哪个按钮有这个效果,与其他按钮有个区别。 */
div.container div.button span.on{
opacity: 1;
}
/* 箭头区 */
div.container .jt{
position: absolute;
top: 40%;
color:greenyellow;
padding: 0px 14px;
font-size: 55px;
text-align: center;
z-index: 2;
display: none;
} div.container .jt_left{
left: 10px;
} div.container .jt_right{
right: 10px;
} div.container:hover .jt{
display: block;
opacity: 0.4;
} div.container .jt:hover{
opacity: 1;
}

为了让刚进页面第一张图显示的是1.jpg,所以在图片区图里面加个行内样式,让默认打开页面显示这个图:

<div class="wrap" style="left:-600px">...</div>
此时效果是这样,当鼠标移动到图片上、箭头处都有一些样式:

3、JS脚本

第一步:实现图片自动切换

封装两个函数:next()、prev()函数,分别对应向右轮播和向左轮播,此时调用哪个函数,就可以向哪个方向一张图片一张图片得切换轮播。

var wrap = document.getElementsByClassName('wrap')[0];

var newLeft = -600;

function next() {
setInterval(function(){
if(newLeft == -2400){
newLeft = 0;
}else{
newLeft = parseInt(wrap.style.left) - 600;
}
wrap.style.left = newLeft + 'PX';
},1000)
} function prev() {
setInterval(function(){
if(newLeft == -600){
newLeft = -3000;
}else{
newLeft = parseInt(wrap.style.left) + 600;
}
wrap.style.left = newLeft + 'PX';
},1000)
}

第二步:让轮播的时候各个图片有运动轨迹地切换,而不是硬生生地从一张图片变到另一张图片。

这里需要用到我封装好的一个运动函数startMove(),做成工具使用:

function getStyle(obj, attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj, false)[attr];
}
} //运动框架 startMove函数
function startMove(obj,json,fn){
clearInterval(obj.timer);
//开启定时器
obj.timer = setInterval(function(){
var flag = true;
//遍历json
for (var attr in json) {
//取当前值 iCur
var iCur = 0;
if (attr == 'opacity') {
iCur = Math.round(parseFloat(getStyle(obj, attr))*100);
}else{
iCur = parseInt(getStyle(obj, attr));
}
//算速度:iSpeed
//目标值:json[attr]
var iSpeed = (json[attr]-iCur)/8;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
//检测停止
if (iCur != json[attr]) {
flag = false
}
if (attr == 'opacity') {
obj.style.filter = 'alpha(opacity:'+iCur+iSpeed+')';
obj.style.opacity = (iCur+iSpeed)/100;
}else{
obj.style[attr] = iCur + iSpeed + 'px';
}
}
if (flag) {
clearInterval(obj.timer);
if (fn) {fn();}
}
},30)
}

这个封装的运动函数这里,加上我的注释还看不懂代码的,可以去看看这个视频,这讲师讲得很清楚:JS动画效果

然后利用这个原理:当图片往右轮播到第六张的时候,马上让第一张呈现出来,紧接着调用封装好的运动函数让从第一张图运动切换到第二张。往左轮播时也是一样的道理,当轮播到第一张的时候马上让第六张呈现出来,紧接着从第六张运动到第五张。这样子从视觉上看来就是五张图片一直循环无缝轮播下去的

这是也为什么要用七张图片,并且第一张图片和第六张一样,第七张和第二张一样的原因。
代码如下:

var wrap = document.getElementsByClassName('wrap')[0];

var newLeft = -600;

function next() {
setInterval(function () {
if (newLeft == -3000) {
newLeft = 0;
wrap.style.left = newLeft + 'px';
}
newLeft -= 600;
startMove(wrap, {
"left": newLeft
})
// wrap.style.left = newLeft + 'PX';
}, 3000)
} function prev() {
setInterval(function () {
if (newLeft == 0) {
newLeft = -3000;
wrap.style.left = newLeft + 'px';
}
newLeft += 600;
startMove(wrap, {
"left": newLeft
});
}, 3000)
}

第三步:使当鼠标移到图片上时,停止自动轮播而让点击几次左右箭头来控制往左右一张一张地轮播几张。

核心原理:清除定时器,绑定click、onmouseenter、onmouseleave事件,重构下代码封装出往右往左轮播函数和自动轮播函数。

往右轮播函数:

function next() {
if (newLeft == -3000) {
newLeft = 0;
wrap.style.left = newLeft + 'px';
}
newLeft -= 600;
startMove(wrap, {
"left": newLeft
});
}

往左轮播函数:

function prev() {
if (newLeft == 0) {
newLeft = -3000;
wrap.style.left = newLeft + 'px';
}
newLeft += 600;
startMove(wrap, {
"left": newLeft
});
}

自动播放函数:

var timer = null;

function autoPlay() {
timer = setInterval(function () {
next();
}, 2000)
} /* 自动播放 */

绑定各个事件:

container.addEventListener('mouseenter', function () {
clearInterval(timer);
}, false) container.addEventListener('mouseleave', function () {
autoPlay();
}, false) left.addEventListener('click', function () {
prev();
}) right.addEventListener('click', function () {
next();
})

第四步:

  • 处理按钮,使刚进页面时,第一个按钮有span元素中类为'on'的效果。
  • 接下来,实现视觉上轮播到哪张图了,就对应哪个按钮有类为'on'的效果。
  • 最后,当你点到哪个按钮时,该按钮有类为'on'的效果,并且跳转到视觉上的第几张图。

封装个处理按钮的函数,功能是给每个按钮的类名设置为空,然后当视觉上移动到第A张图时,就让此时这第A个按钮的类型为'on'。

所以需要设置个哨兵index监听这是视觉上第几张图,然后为这张图对应的按钮添加'on'类:

//处理按钮
var index = 0;
var len = dot.length;
function setCurrentDot(){
for (var m = 0; m < len; m++){
dot[m].className = '';
}
dot[index].className = 'on';
}
setCurrentDot();

此时调用了这个函数的话,就等于刚进入页面的时候默认显示的第一张图片也是默认让第一个按钮有'on'类的效果。

那怎么让当视觉上移动到第A张图时,就让此时这第A个按钮的类型为'on'呢?

可以在轮播一次的函数里加入修改index哨兵的值并且调用setCurrentDot()函数。在next()中:

    index++;
if(index === 5){
index = 0;
}
setCurrentDot();

在prev()中:

    index--;
if(index === -1){
index = 4;
}
setCurrentDot();

最后,实现点到哪个按钮时,该按钮有类为'on'的效果,并且跳转到视觉上的第几张图。

核心思路:当点击该按钮时,比如点了第三个按钮,那么此时应该显示的图片应该是视觉上第三张图片也就是七张图片中的第四张,第四张对应的wrap的left为-1800px,然后找出对应的规律,此时的newLeft就应该为:-600 * (x + 1)。那么不管在点击按钮前已经轮播到哪里了,只要在点击后,使用运动函数startMove()移动到这个newLeft位置处就行了。按例子来说此时的哨兵index也等于3,因为点了第几个按钮肯定就第几个按钮有'on'类咯。

根据核心思路写出代码为(这里需要注意绑定事件时的闭包问题):

// 点到哪个按钮时,该按钮有类为'on'的效果,并且跳转到视觉上的第几张图。
for (var s = 0; s < len; s++){
(function(s){
dot[s].addEventListener('click',function(){
newLeft = -600 * (s + 1);
startMove(wrap,{"left":newLeft});
index = s;
setCurrentDot();
},false)
}(s))
}

写到这里,所以需求就做完了。

最后

思路就是这样,重要的不是代码,是分析逻辑。
源码已传到github,觉得对您有帮助的,麻烦点个star,谢谢~

授人以渔式解析原生JS写轮播图的更多相关文章

  1. 原生Js写轮播图代码

    html css js 在知道jQuery如何实现轮播效果的基础上,用js写代码 如图:标记这里的地方 理解一下 用到的知识: 1.HTML DOM 的appendChild() 和 removeCh ...

  2. 原生js写轮播图效果

    <script> var picarr=[ "pic/lb1.jpg", "pic/lb2.jpg", "pic/lb3.jpg" ...

  3. 原生js焦点轮播图的实现

    继续学习打卡,武汉加油,逆战必胜!今日咱们主要探讨一下原生js写轮播图的问题, 简单解析一下思路: 1,首先写好css样式问题 2,考虑全局变量:自动播放的定时器,以及记录图片位置的角标Index 2 ...

  4. 封装一个简单的原生js焦点轮播图插件

    轮播图实现的效果为,鼠标移入左右箭头会出现,可以点击切换图片,下面的小圆点会跟随,可以循环播放(为了方便理解,没有补2张图做无缝轮播).本篇文章的主要目的是分享封装插件的思路. 轮播图我一开始是写成非 ...

  5. 原生JS实现轮播图的效果

    原生JS实现轮播图的效果: 只要缕清了全局变量index的作用,这个轮播图也就比较容易实现了:另外,为了实现轮这个效果,有几处clearInterval()必须写上.废话不多说,直接上代码,修复了几个 ...

  6. 使用原生js将轮播图组件化

    代码地址如下:http://www.demodashi.com/demo/11316.html   这是一个轮播图组件,这里是代码地址,需要传入容器的id和图片地址,支持Internet Explor ...

  7. 原生js焦点轮播图

    原生js焦点轮播图主要注意这几点: 1.前后按钮实现切换,同时注意辅助图2.中间的button随着前后按钮对应切换,同时按button也能跳转到相应的index3.间隔调用与无限轮播.4.注意在动画时 ...

  8. 原生js实现轮播图

    原生js实现轮播图 很多网站上都有轮播图,但找到一个系统讲解的却很难,因此这里做一个简单的介绍,希望大家都能有所收获,如果有哪些不正确的地方,希望大家可以指出. 原理: 将一些图片在一行中平铺,然后计 ...

  9. 用原生js封装轮播图

    原生js封装轮播图 对于初学js的同学来说,轮播图还是一个难点,尤其是原生js封装轮播图代码,下面是我之前做的一个轮播图项目中封装好的一些代码,有需要的同学可以看一下,有什么不懂的可以看注释,注释看不 ...

随机推荐

  1. SpringBoot开发二十-Redis入门以及Spring整合Redis

    安装 Redis,熟悉 Redis 的命令以及整合Redis,在Spring 中使用Redis. 代码实现 Redis 内置了 16 个库,索引是 0-15 ,默认选择第 0 个 Redis 的常用命 ...

  2. [LC] 124. Binary Tree Maximum Path Sum

    Given a non-empty binary tree, find the maximum path sum. For this problem, a path is defined as any ...

  3. Grails Controller - redirect 方法

    官方文档: http://docs.grails.org/latest/ref/Controllers/redirect.html 网页跳转方法1: // 在一个Action中直接跳转到另外一个Act ...

  4. JavaScript学习总结(一)基础部分

    转自:http://segmentfault.com/a/1190000000652749 基本概念 javascript是一门解释型的语言,浏览器充当解释器. js执行引擎并不是一行一行的执行,而是 ...

  5. NEON优化之《简介》

    NDK支持NEON环境配置:https://blog.csdn.net/app_12062011/article/details/50462351 一个很典型的例子:http://hilbert-sp ...

  6. rancher2.0快速入门

    注意:本入门指南的目的是让您快速的运行一个Rancher2.0环境,它不适用于生产.有关更全面的说明,请查阅Rancher安装. 本教程将指导您完成: 安装Rancher v2.0 : 创建第一个集群 ...

  7. PO设计模式-实现移动端自动化测试

    开发环境:python 3.6.5 + selenium 2.48.0 + pytest框架 + Android 5.1 工具:pycharm + Appium + Genymotion 测试机型:S ...

  8. [洛谷P3384] [模板] 树链剖分

    题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...

  9. 自定义一个简单的SegmentedControl

    先大概看下我们想实现简单的效果 源码 // // DSegmentedControl.swift // IOS学习之自定义UISegmentedControl // // Created by din ...

  10. zookeeper 单机部署

    第一步:下载安装包 这里以3.4.11为例  https://archive.apache.org/dist/zookeeper/ 点进去看: 下载tar文件 第二步:上传到服务器 使用ftp工具上传 ...