用原生的javascript 实现一个无限滚动的轮播图
说一下思路:和我上一篇博客中用JQ去写的轮播图有相同点和不同点
相同点:
- 首先页面布局是一样的
- 同样是改变.inner盒子的位置去显示不同的图片
不同点:
- 为了实现无限滚动需要多添加两张重复的图片
- 左右切换和前面的方法有所不同,前面是获取当前的索引值乘以-600px当做位移距离,现在是需要获取当前.inner的位置来加上或者减去-600来实现
下面来一步步的去实现轮播图:
首先是html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
ul{
list-style: none;
position: absolute;
bottom: 0;
left: 175px;
}
ul li{
float: left;
}
ul li a{
display: block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #ffbeaa;
margin-left: 5px;
opacity: 0.6;
}
ul li a.active{
background-color: red;
}
.inner{
width: 4200px;
height: 400px;
position: absolute;
}
.inner img{
display: block;
float: left;
}
.pic{
height: 400px;
width: 600px;
overflow: hidden;
position: relative;
}
.prev,.next{
position: absolute;
top: 190px;
opacity: 0.6;
}
.next{
right: 0;
}
</style>
<script> </script>
</head>
<body>
<div class="pic" id="pic">
<div class="inner" id="inner" style="left:-600px;">
<img src="img/5.jpg" alt="">
<img src="img/1.jpg" alt="">
<img src="img/2.jpg" alt="">
<img src="img/3.jpg" alt="">
<img src="img/4.jpg" alt="">
<img src="img/5.jpg" alt="">
<img src="img/1.jpg" alt="">
</div>
<ul id="ul">
<li><a href="#" class="active" id="1"></a></li>
<li><a href="#" id="2"></a></li>
<li><a href="#" id="3"></a></li>
<li><a href="#" id="4"></a></li>
<li><a href="#" id="5"></a></li>
</ul>
<a href="#" class="prev" id="prev"><img src="img/slider-prev.png" alt=""></a>
<a href="#" class="next" id="next"><img src="img/slider-next.png" alt=""></a>
</div>
</body>
</html>
第一步添加左右点击切换:
<script>
//文档加载完毕后执行函数
window.onload=function(){
var pic = document.getElementById("pic");
var inner = document.getElementById("inner");
var li = document.getElementById("ul").getElementsByTagName("a");
var prev = document.getElementById("prev");
var next = document.getElementById("next");
//设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色
var index = 1;
//左点击事件
prev.onclick = function(){
//调用动画函数,传入正的600,为每次的偏移量
animate(600);
//设置索引的范围,不能小于1
if(index==1){
index=5;
}else{
index--;
}
//调用添加颜色函数
showButton();
}
//右点击事件
next.onclick = function(){
//调用动画函数,传入负的600,为每次的偏移量
animate(-600);
//设置索引的范围,不能超过5
if(index==5){
index=1;
}else{
index++;
}
showButton();
}
//动画函数,offset参数为偏移量
function animate(offset){
//获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子
inner.style.left = parseInt(inner.style.left) + offset + "px";
//判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px
if(parseInt(inner.style.left) < -3000){
inner.style.left = -600 + "px";
}
if(parseInt(inner.style.left) > -600){
inner.style.left = -3000 + "px";
}
}
//按钮添加颜色函数
function showButton(){
//遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类
for(var i=0;i<li.length;i++){
if(li[i].className=="active"){
li[i].className="";
//移除后就没必要去循环了,做一个优化。
break;
}
}
//根据当前的index值,找到对应的a元素添加active类
li[index-1].className="active";
}
}
</script>
需要注意的地方:
- 执行完毕inner.style.left = parseInt(inner.style.left) + offset + "px"; 后 inner.style.left的值为新位置的值,后面的判断需要用新的值去判断
- index的值为1-5,做成a元素的下标时需要 index-1
- 注意调用的showButton函数的位置,需要在得到index的值的后调用
- 需要给.inner盒子添加行内样式 style="left:-600px;",不添加出现inner.style.left获取不到值的情况
- 获取a元素不能 var li = document.getElementById("ul").getElementsByTagName("li").getElementsByTagName("a");去获取,因为getElementsByTagName("li")获取的是一个包含5个li的数组,需要加索引值,比如var li = document.getElementById("ul").getElementsByTagName("li")[0].getElementsByTagName("a");
第二步:添加五个按钮切换
<script>
//文档加载完毕后执行函数
window.onload=function(){
var pic = document.getElementById("pic");
var inner = document.getElementById("inner");
var li = document.getElementById("ul").getElementsByTagName("a");
var prev = document.getElementById("prev");
var next = document.getElementById("next");
//设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色
var index = 1;
//左点击事件
prev.onclick = function(){
//调用动画函数,传入正的600,为每次的偏移量
animate(600);
//设置索引的范围,不能小于1
if(index==1){
index=5;
}else{
index--;
}
//调用添加颜色函数
showButton();
}
//右点击事件
next.onclick = function(){
//调用动画函数,传入负的600,为每次的偏移量
animate(-600);
//设置索引的范围,不能超过5
if(index==5){
index=1;
}else{
index++;
}
showButton();
}
//动画函数,offset参数为偏移量
function animate(offset){
//获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子
inner.style.left = parseInt(inner.style.left) + offset + "px";
//判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px
if(parseInt(inner.style.left) < -3000){
inner.style.left = -600 + "px";
}
if(parseInt(inner.style.left) > -600){
inner.style.left = -3000 + "px";
}
}
//按钮添加颜色函数
function showButton(){
//遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类
for(var i=0;i<li.length;i++){
if(li[i].className=="active"){
li[i].className="";
//移除后就没必要去循环了,做一个优化。
break;
}
}
//根据当前的index值,找到对应的a元素添加active类
li[index-1].className="active";
}
//遍历五个按钮
for(var i=0;i<li.length;i++){
//给五个按钮添加点击事件
li[i].onclick=function(){
//获取当前的id值
var id = parseInt(this.getAttribute("id"));
//减去原来的index值,乘以-600 得到偏移量,调用偏移函数
var offset = (id-index) * -600;
//调用偏移函数
animate(offset);
//把index的值更新
index = id;
//调用改变背景色函数
showButton();
}
}
}
</script>
需要注意:
- 第72行 index = id 把index的值更新为当前的索引index。
- 因为id属性不是HTML自带的属性。不能li.style.id 这样去获取,而是使用getAttribute("id")方法,这个方法HTML自带属性和自定义属性都能获取
第三步:添加animate函数添加动画函数
<script>
window.onload=function(){
var pic = document.getElementById("pic");
var inner = document.getElementById("inner");
var li = document.getElementById("ul").getElementsByTagName("a");
var prev = document.getElementById("prev");
var next = document.getElementById("next");
var index = 1;
//通过state的状态 来判断是否执行animate函数
var state = false;
prev.onclick = function(){
//如果state=false 代表动画函数没有执行完毕,则此次点击无效
if(state){
return;
}
animate(600);
if(index==1){
index=5;
}else{
index--;
}
showButton();
}
next.onclick = function(){
//如果state=false 代表动画函数没有执行完毕,则此次点击无效
if(state){
return;
}
animate(-600);
if(index==5){
index=1;
}else{
index++;
}
showButton();
} function animate(offset){
//调用animate函数后 state的值变为true
state = true;
//动画执行总的时间
var time = 300;
//每次位移的间隔时间
var interval = 10;
//每次位移量
var speed = offset/(time/interval); var newLeft = parseInt(inner.style.left) + offset;
//动画函数
function go(){
if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){
inner.style.left = parseInt(inner.style.left) + speed + "px";
//通过延时定时器不断的去调用自身go函数。直到达到目标位置
setTimeout(go,interval);
}else{
//达到目标位置后 state 状态变为 false
state = false;
//跟新.inner盒子的值为目标的位置
inner.style.left = newLeft + "px";
//盒子到达目标位置后做一个判断,如果跑到假的第一张图和第五张图上时,马上瞬间跑到真正的第一张图或者第五张图
if(parseInt(inner.style.left) < -3000){
inner.style.left = -600 + "px";
}
if(parseInt(inner.style.left) > -600){
inner.style.left = -3000 + "px";
}
}
}
go(); }
function showButton(){
for(var i=0;i<li.length;i++){
if(li[i].className=="active"){
li[i].className="";
break;
}
}
li[index-1].className="active";
}
for(var i=0;i<li.length;i++){
li[i].onclick=function(){
var id = parseInt(this.getAttribute("id"));
var offset = (id-index) * -600;
//如果state=false 代表动画函数没有执行完毕,则此次点击无效
if(state){
return;
}
animate(offset);
index = id;
showButton();
}
}
}
做这个go函数我觉得是这个轮播图中最难的点,我经常有地方转不过弯来。
需要注意的地方:
- 每次位移一小段距离,终点怎么去判断,也就是什么时候会停止,.inner盒子只能往左边或者右边移动,点击next按钮 .inner往左边移动,是添加一个负值距离,点击prev按钮 .inner往右移动,是添加一个正的left距离 第52行判断条件的意思是,如果speed小于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果大于他则不停的去加上-speed去变小 与newLeft相同为止 或者speed大于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果小于他则不停的去加上speed去变大 与 newLeft相同为止。
- newLeft = parseInt(inner.style.left) + offset; 表示最终目标值,存进了变量newLeft中,下面inner.style.left获取的都是现在的left值
- go函数里面用的是setTimeout()来递归,通过判断条件,来递归go函数。开始我用的是setInterval()方法,导致出现了奇异的动画效果,思路错了,应该在if前面添加一个clearInterval()清除方法,因为如果不清除的话会不断的调用go函数,导致go函数永远都不会结束,就导致了画面狂闪现象。 setTimeout()方法是在什么时间以后干什么,干完拉倒。setInterval()不停的去调用函数,直到clearInterval()被调用或者窗口被关闭。
- 注意第70行,写完go函数后需要调用他才会执行。
第四步:最终版,添加自动轮播效果
<script>
window.onload=function(){
var pic = document.getElementById("pic");
var inner = document.getElementById("inner");
var li = document.getElementById("ul").getElementsByTagName("a");
var prev = document.getElementById("prev");
var next = document.getElementById("next");
var index = 1;
var timer = null;
//设置一个变量来存放自动轮播定时器
var timer2 = null;
var state = false;
prev.onclick = function(){
if(state){
return;
}
animate(600);
if(index==1){
index=5;
}else{
index--;
}
showButton();
}
next.onclick = function(){
if(state){
return;
}
animate(-600);
if(index==5){
index=1;
}else{
index++;
}
showButton();
} function animate(offset){
state = true;
var time = 300;
var interval = 10;
var speed = offset/(time/interval); var newLeft = parseInt(inner.style.left) + offset;
function go(){
clearInterval(timer);
if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){
inner.style.left = parseInt(inner.style.left) + speed + "px";
timer=setInterval(go,interval);
}else{
state = false;
inner.style.left = newLeft + "px";
if(parseInt(inner.style.left) < -3000){
inner.style.left = -600 + "px";
}
if(parseInt(inner.style.left) > -600){
inner.style.left = -3000 + "px";
}
}
}
go(); }
function showButton(){
for(var i=0;i<li.length;i++){
if(li[i].className=="active"){
li[i].className="";
break;
}
}
li[index-1].className="active";
}
for(var i=0;i<li.length;i++){
li[i].onclick=function(){
var id = parseInt(this.getAttribute("id"));
var offset = (id-index) * -600;
if(state){
return;
}
animate(offset);
index = id;
showButton();
}
}
//通过定时器来不断的点击 next按钮 来实现轮播效果.
function play(){
timer2 = setInterval(function(){
next.onclick();
},3000);
}
//停止轮播函数,清除定时器
function stop(){
clearInterval(timer2);
}
//给.pic添加移进悬浮和移出事件
pic.onmouseover = stop;
pic.onmouseout = play;
//第一次访问页面开始轮播
play();
}
</script>
需要注意的地方:
- 触发next的点击事件,可以写成next.onclick()来触发
- 给.pic添加事件 不能写成pic.onmouseover = stop(),加了括号后代表立即调用函数,而不是我们需要的悬浮在pic盒子上时调用.
总结:第一次学习这个轮播图时,因为思路跟不上,导致看不懂,然后我又从简单的做起,比如我先学习做了一个自动轮播标签页(前面博客有总结),然后又学习用jq写了一个简单的轮播图,再过来学习这个难度大的,循序渐进去学习,就会发现自己能懂甚至写出来这个轮播图了,附上我学习的视频链接地址。
标签切换地址:http://www.imooc.com/learn/176
JQ轮播图地址:http://www.cnblogs.com/yewenxiang/p/6100206.html
原生js轮播图地址:http://www.imooc.com/learn/176
这篇博客是我目前写的最长的一篇,时间跨度两天,中间多有疏漏或者不正确的地方还希望能指出,我改正。
用原生的javascript 实现一个无限滚动的轮播图的更多相关文章
- 一步一步拆解一个简单的iOS轮播图(三图)
导言(可以不看): 不吹不黑,也许是东半球最简单的iOS轮播图拆分注释(讲解不敢当)了(tree new bee).(一句话包含两个人,你能猜到有谁吗?提示:一个在卖手机,一个最近在卖书)哈哈... ...
- 带无缝滚动的轮播图(含JS运动框架)
今天学习了一下轮播图的写作,想到前一阵学过的无缝滚动得思想,所以就把轮播与滚动结合了一下.不过我的代码的神逻辑我自己都不敢恭维,在没网没参照的情况下,只能硬着头皮往下写,希望跟大家共勉吧. js运动框 ...
- 自定义完美的ViewPager 真正无限循环的轮播图
网上80%的思路关于Android轮播图无限循环都是不正确的,不是真正意义上的无限循环, 其思路大多是将ViewPager的getCount方法返回值设置为Integer.MAX_VALUE, 然后呢 ...
- jquery一个比较好的轮播图jQuery.kinMaxShow介绍
kinMaxShow API 可选参数以及详解 kinMaxShow 主参数详解 参数名称 默认值 简单释义 height 500 [整型 (单位:像素)]焦点图高度,必须设置 缺省则启用默认高度 5 ...
- javascript写淡入淡出效果的轮播图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 带无缝滚动的轮播图(含JS运动框架)-简洁版
昨天写的神逻辑,今天终于解决,经过大家的商讨,终于研究出来一套简单的代码!!! js代码如下: <script> window.onload = function() { var oWra ...
- 京东首页原生----js制作|css动画|js动画|计时器--轮播图(好久没更新,这两天闲的蛋疼做个京东页面分辨率1366*768,919京东,适应没调!)要文件加关注找我要哦!
- vue 写一个炫酷的轮播图
效果如上图: 原理: 1.利用css 的 transform 和一些其他的属性,先选五张将图片位置拍列好,剩余的隐藏 2.利用 js 动态切换类名,达到切换效果 css代码如下 .swiper-cer ...
- 原生js实现响应式轮播图,支持电脑端点击切图,手机端滑动切图
轮播图的实现原理并不难,但是步骤有些繁琐.最近练习了一个轮播图,大部分是跟着网上的教程写的,然后自己做了一点兼容ie8的修改,加了点击切换图片的特效和手机端的滑动特效,让这个轮播图可以在响应式的网站中 ...
随机推荐
- bat 笔记 一
echo 有两个参数 off 和 on 注意echo前面要加个@才生效 当 @echo off的时候就是将doc命令将前面的路径去掉,默认其实就是@echo on显示路径: 默认的状态: 输入@ech ...
- Ztree学习(-)简单例子
https://www.cnblogs.com/shinhwazt/p/5828031.html ztree包:https://pan.baidu.com/s/1vOgGm_elF-lF0VowoHw ...
- MonoDevelop 设置
菜单:Tools->Options Text Editor Behavior Automatic behaviors × enable on the fly code formatting Sy ...
- 常用类一一基本数据类型的包装类(WrapperClass)一一Byte Short nteger Long Float Double Character Boolean
为什么需要包装类? JAVA是支持跨平台的.可以在服务器 也可以在手机上运行 基本数据类型 在栈中 效率更高 包装类 将数据类型转换成对象 在 堆中 利于操作 package cn.bjsxt.w ...
- python面试题(转)
下面的代码输出什么? list = ['a', 'b', 'c', 'd', 'e'] print list[10:] 上面的代码输出[],并且不会导致IndexError错误 跟你想的一样,当取列表 ...
- 贝叶斯vs频率派:武功到底哪家强?| 说人话的统计学·协和八(转)
回我们初次见识了统计学理论中的“独孤九剑”——贝叶斯统计学(戳这里回顾),它的起源便是大名鼎鼎的贝叶斯定理. 整个贝叶斯统计学的精髓可以用贝叶斯定理这一条式子来概括: 我们做数据分析,绝大多数情况下希 ...
- Gradle with Android
[Gradle with Android] The Android Studio build system is based on Gradle, and the Android plugin for ...
- HTTP协议图示详解
一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. ...
- input disable手机端颜色兼容问题
color: #5b636d; -webkit-text-fill-color: #5b636d; opacity: 1; -webkit-opacity: 1; input在移动端会有padding ...
- ubuntu下 openvpn客户端的配置
1.安装openvpn sudo apt-get install openvpn 2.配置openvpn 作为客户端,OpenVPN并没有特定的配置文件,而是由服务器提供方给出一个配置文件.对于认证, ...