思路:首先要知道需求,先从简单的地方入手,然后一步一步的去改进,但是首先要想好做每一步目的,原因,不要只知道代码是这么写的,而不去想为什么要这么做。
动画函数封装
function animate(obj, target, callback) { //做动画的对象,需要移动的距离,回调函数
clearInterval(obj.timer);
obj.timer = setInterval(function() {
var step = (target - obj.offsetLeft) / 10;//缓动动画实现原理
step = step > 0 ? Math.ceil(step) : Math.floor(step); //取整的问题,否者后面会有瑕疵
if(obj.offsetLeft == target){ //判断时候到达位置
clearInterval(obj.timer); //清除定时器
obj.timer = null; //将该对象的定时器设置为空,释放内存
callback && callback(); //如果有回调函数就调用回调函数
}
obj.style.left = obj.offsetLeft + step + 'px'; //移动
}, 15);
}
1,首先获取几个等会肯定要用到的元素;
var arrowLeft = document.querySelector('.arrow-l'); //获取左右两个小箭头
var arrowRight = document.querySelector('.arrow-r');
var focus = document.querySelector('.center'); //获取父盒子
var focusWidth = focus.offsetWidth; //得到父盒子的宽度,一会图片的切换需要用到
var ul = focus.querySelector('ul');//获取ul,为ol动态创建li做准备
var ol = focus.querySelector('ol');
2,原先左右的两个小箭头是隐藏的,只有当鼠标经过了它们所在的父盒子,它们才会显示,所以可以为 focus 添加监听事件了
focus.addEventListener('mouseenter', function() { //当鼠标经过时显示
arrowRight.style.display = arrowLeft.style.display = 'block';
});
focus.addEventListener('mouseleave', function() { //离开隐藏
arrowRight.style.display = arrowLeft.style.display = 'none';
}
3,一般到了后面会不确定每次的轮播图的图片有几张,所以与图片所对应的小圆点建议动态的创建,根据图片的个数,来创建对应的圆点个数
for(var i = 0; i < ul.children.length; i++){
var li = document.createElement('li');
li.setAttribute('index', i);//再创建li的同时给它设置一个索引号,后面会用到
li.addEventListener('click', fn3);//再给它们添加点击事件
ol.appendChild(li); //追加到ol中
}
function fn3() { //点击每个小圆点所做的事
for(var i = 0; i < ol.children.length; i++){ //排他思想,将所有的小圆点的样式都先去掉
ol.children[i].className = '';
}
var index = this.getAttribute('index'); //获取图片的索引值
animate(ul, -index * focusWidth);//开始做移动效果,根据你所点击的小圆点的索引值,
//乘以一个盒子的宽度,就是ul索要移动的距离,
this.className = 'current'; //再设置你所点击的小圆点的样式
}
ol.children[0].className = 'current'; //默认的显示为第一张图片,所以要设置第一个小圆点的样式
4,添加点击左侧按钮事件,
ul.appendChild(ul.children[0].cloneNode(true)); //克隆第一张图片,做无缝切换,
//一定要放在创建小圆点的后面,因为小圆点的跳转比较简单,不用做无缝切换,
var num = 0; //为了来控制图片所再的位置
var circle = 0; //为了来控制与图片所对应的小圆点的样式
arrowLeft.addEventListener('click', fn4); //添加点击事件
function fn4() {
if(num == 0){ //判断如果当前图片是不是第一张,
num = ul.children.length - 1; //如果时就将num等于我们克隆出来的图片的位置,也就是最后一个
ul.style.left = -num * focusWidth + 'px'; //立马将ul移动到最后一张图片,不做动画效果
}
num--; //--了以后就是指向真正的最后一张图片,就是原始的最后一张
circle--; //小圆点的位置也要发生改变
if(circle < 0){ //判断--了以后是否小于零了
circle = ol.children.length - 1; //如果小于零了就将它设为最后一个小圆点的索引
}
for(var i = 0; i < ol.children.length; i++){ //还是排他思想,
ol.children[i].className = '';//去掉其他所有的样式
}
ol.children[circle].className = 'current'; //给当前索引的小圆点添加样式
animate(ul, -num * focusWidth);//做动画
}
5,因为有的用户会直接点击小圆点,然后再点击左右箭头,所以会导致num个circle的值不准,所以我们要做个修改,再小圆点的点击方法里该
function fn3() { //点击每个小圆点所做的事
for(var i = 0; i < ol.children.length; i++){ //排他思想,将所有的小圆点的样式都先去掉
ol.children[i].className = '';
}
var index = this.getAttribute('index'); //获取图片的索引值。
num=circle=index; //将你所点击的索引值同步给num和circle就可以解决了
animate(ul, -index * focusWidth);//开始做移动效果,根据你所点击的小圆点的索引值,
//乘以一个盒子的宽度,就是ul索要移动的距离,
this.className = 'current'; //再设置你所点击的小圆点的样式
}
6,为右侧添加点击事件 大部分的原理与左侧相同,所以我就不做过多的解释了
arrowRight.addEventListener('click',fn5);
function fn5() {
if(num==ul.children.length-1){ //因为是右移,所以时判断是不是最后一张图(克隆出来的图片)
num=0;
ul.style.left=-num*focusWidth+'px'; //是的话立马进行跳转至第一张图
}
num++;
circle++;
if(circle==ol.children.length){
circle=0; //与上面同理
}
for(var i = 0; i < ol.children.length; i++){ //还是排他思想,
ol.children[i].className = '';//去掉其他所有的样式
}
animate(ul,-num*focusWidth)
}
7,给页面添加自动轮播的方法,就是添加一个定时器,然后每次自动调用右侧点击按钮事件就可以了,不用再重新写一份代码了
var timer=setInterval(function() {
arrowRight.click();
},2000); //超级简单
8,根据这些代码,可以完成动画了,但是这样子有一个缺点,就是当用户非常快的点击左右两侧的按钮,图片也会跳转的非常的快,所以我们要做一个节流阀,就是为了防止用户点击过快,用户每次点击两侧按钮,需要等上一次所点击的动画完成后才有效,做起来非常简单
var flag=true; //声明一个切换true与false的变量
然后再每个点击事件里面首先做一个判断,flag是否为真,为真就进入做动画,做动画前将flag改为false,再动画做完后做一个回调函数,这个回调函数里面就写flag=true
以点击右侧为例:
arrowRight.addEventListener('click',fn5);
function fn5() {
if(flag){ //判断
flag=false; //修该, 如果用户点击过快,上一次的动画还没结束,flag都为false,
//就不能再进入了,也就不能开始做动画了
if(num==ul.children.length-1){
num=0;
ul.style.left=-num*focusWidth+'px';
}
num++;
circle++;
if(circle==ol.children.length){
circle=0;
}
circleChange(); //我将这里原先的代码封装起来了,左右两侧的代码相同
animate(ul,-num*focusWidth,function(){flag=true}) //等动画做完后执行这个回调函数,将flag改为true,就可以再进行下一次的动画了
}
}
整个页面代码如下 (有些与上面的不同是我做了一些小的优化)
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: 0;
padding: 0;
}
a{
text-decoration: none;
color: white;
}
li{
list-style: none;
}
.center{
position: relative;
width: 721px;
margin: auto;
overflow: hidden;
height: 455px;
}
.center ul{
position: absolute;
width: 500%;
}
.center ul li{
float: left;
}
.arrow-l, .arrow-r{
display: none;
width: 24px;
height: 40px;
text-align: center;
line-height: 40px;
background-color: rgba(0, 0, 0, .3);
color: white;
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 2;
}
.arrow-l{
border-top-right-radius: 50%;
border-bottom-right-radius: 50%;
}
.arrow-r{
right: 0;
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.circle{
position: absolute;
bottom: 10px;
left: 50px;
}
.circle li{
float: left;
width: 8px;
height: 8px;
/*background-color: #fff;*/
border: 2px solid rgba(255, 255, 255, 0.5);
margin: 0 3px;
border-radius: 50%;
/*鼠标经过显示小手*/
cursor: pointer;
}
.current{
background-color: #fff;
}
</style>
</head>
<body>
<div class="center">
<a href="javascript:;" class="arrow-l"><</a>
<a href="javascript:;" class="arrow-r">></a>
<ul>
<li>
<a href="javascript:;"><img src="img/focus.jpg" alt=""></a>
</li>
<li>
<a href="javascript:;"><img src="img/focus1.jpg" alt=""></a>
</li>
<li>
<a href="javascript:;"><img src="img/focus2.jpg" alt=""></a>
</li>
<li>
<a href="javascript:;"><img src="img/focus3.jpg" alt=""></a>
</li>
</ul>
<ol class="circle"></ol>
</div>
<script>
function animate(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function() {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(obj.offsetLeft == target){
clearInterval(obj.timer);
obj.timer = null;
callback && callback();
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var arrowLeft = document.querySelector('.arrow-l'); //获取左右两个小箭头
var arrowRight = document.querySelector('.arrow-r');
var focus = document.querySelector('.center');
var focusWidth = focus.offsetWidth;
var ul = focus.querySelector('ul');//获取ul,为ol动态创建li做准备
var ol = focus.querySelector('ol');
focus.addEventListener('mouseenter', fn1);
function fn1() {
arrowRight.style.display = arrowLeft.style.display = 'block';
clearInterval(timer);
timer=null;
}
focus.addEventListener('mouseleave', fn2);
function fn2() {
arrowRight.style.display = arrowLeft.style.display = 'none';
timer=setInterval(function() {
arrowRight.click();
},2000);
}
for(var i = 0; i < ul.children.length; i++){
var li = document.createElement('li');
li.setAttribute('index', i);
li.addEventListener('click', fn3);
ol.appendChild(li);
}
function fn3() {
if(flag){
flag=false;
for(var i = 0; i < ol.children.length; i++){
ol.children[i].className = '';
}
var index = this.getAttribute('index');
num = circle = index;
animate(ul, -num * focusWidth,function(){flag=true});
this.className = 'current';
}
}
ol.children[0].className = 'current';
ul.appendChild(ul.children[0].cloneNode(true)); //克隆第一张图片,做无缝切换
var num = 0;
var circle = 0;
var flag = true;
arrowLeft.addEventListener('click', fn4);
function fn4() {
if(flag){
flag=false;
if(num == 0){
num = ul.children.length - 1;
ul.style.left = -num * focusWidth + 'px';
}
num--;
circle--;
if(circle < 0){
circle = ol.children.length - 1;
}
circleChange();
animate(ul, -num * focusWidth,function() {flag=true});
}
}
arrowRight.addEventListener('click',fn5);
function fn5() {
if(flag){
flag=false;
if(num==ul.children.length-1){
num=0;
ul.style.left=-num*focusWidth+'px';
}
num++;
circle++;
if(circle==ol.children.length){
circle=0;
}
circleChange();
animate(ul,-num*focusWidth,function(){flag=true})
}
}
var timer=setInterval(function() {
arrowRight.click();
},2000);
function circleChange() {
for(var i = 0; i < ol.children.length; i++){
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
}
</script>
</body>
</html>
来源:https://blog.csdn.net/qq_41189709/article/details/98722383