<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				padding: 0;
				margin: 0;
				list-style: none
			}

			#wrap {
				width: 960px;
				height: 320px;
				border: 2px solid red;
				margin: 50px auto;
				position: relative;
				overflow: hidden;
			}

			#wrap img {
				width: 960px;
				height: 320px;
			}

			#wrap ul {
				width: 3840px;
				position: absolute;
			}

			#wrap li {
				float: left;
			}

			#wrap p {
				position: absolute;
				bottom: 20px;
				width: 100%;
				text-align: center;
			}

			#wrap span {
				padding: 2px 8px;
				background: blue;
				color: #fff;
				margin-right: 4px;
				cursor: pointer;
			}

			#wrap .active {
				background: red;
			}
		</style>
		
	</head>
	<body>
		<div id="wrap">
			<!--2.图片列表-->
			<ul>
				<!-- <li><img src="img/1.jpg" alt=""></li>
		            <li><img src="img/2.jpg" alt=""></li>
		            <li><img src="img/3.jpg" alt=""></li>
		            <li><img src="img/4.jpg" alt=""></li> -->
			</ul>
			<p>
				<!-- <span class="active">1</span><span>2</span><span>3</span><span>4</span> -->
			</p>
		</div>
	</body>
</html>

js文件 

window.onload = function() {
	//1 获取元素
	var ul = document.getElementsByTagName('ul')[0];
	var p = document.getElementsByTagName('p')[0];
	var wrap = document.getElementById('wrap');
	//2 动态渲染页面
	var imgArr = ['./img/1.jpg', './img/2.jpg', './img/3.jpg', './img/4.jpg'];
	for (var i = 0; i < imgArr.length; i++) {
		//创建li
		var li = document.createElement('li');
		li.innerHTML = '<img src="' + imgArr[i] + '">';
		//追加到ul
		ul.appendChild(li);
		//创建序号按钮
		var span = document.createElement('span');
		span.innerText = i + 1;
		p.appendChild(span);
	}
	//3 初始化默认样式
	p.children[0].className = 'active';

	//4实现自动轮播
	//轮播图自动轮播  当鼠标移入的时候 停止轮播  当鼠标移出的时候 重新开始轮播
	//ul的定位是 -被推出的图片个数 * 图片宽度(960)
	//声明一个计数变量  用来记录从div左侧被推出去的图片个数
	var n = 0;
	// console.log(ul.children[0].offsetWidth)	可以获取li的宽度
	//4.1 每隔2s 移动一次
	function auto() {
		//如果当前显示假0  就定位到 真0 之后往真1走
		if (n >= 4) {
			// 定位到 真0
			ul.style.left = 0;
			n = 0;
		}
		//让ul向左走一张图宽	计算图片或li的宽度
		n++;
		var end = -(n * 960);
		bufferMove(ul, {
			left: end
		});
		//设置序号对应	排他思想
		for (var j = 0; j < p.children.length; j++) {
			p.children[j].className = '';
		}
		// 如果当前显示的是假0 就让序号1亮起
		if (n >= 4) {
			p.children[0].className = 'active';
		} else {
			p.children[n].className = 'active';
		}
	}

	//执行动画
	var timer = setInterval(auto, 3000);

	//4.2 当鼠标移入 清除定时器
	wrap.onmouseover = function() {
		clearInterval(timer);
	}
	//4.3 当鼠标移出 从新添加定时器
	wrap.onmouseout = function() {
		timer = setInterval(auto, 3000);
	}

	//5 无缝轮播
	//在ul的最后面添加一张假图片  假的第一张图片
	var fade = ul.children[0].cloneNode(true);
	ul.appendChild(fade);
	//5.1 动态修改ul宽度 ul width == li个数 * li宽度
	ul.style.width = ul.children.length * 960 + 'px';
	//6 点击序号实现切换
	var spanS = document.getElementsByTagName('span');
	for (var i = 0; i < spanS.length; i++) {
		//自定义索引
		spanS[i].idx = i;
		spanS[i].onclick = function() {
			//切换到对应图片  ul定位终点值 -图片下标 * 图宽
			//由于序号下标和 图片下标一一对应,因此可以使用序号下标替代图片下标   ul定位终点值 : -序号下标 * 图宽
			var end = -this.idx * 960;
			bufferMove(ul, {
				left: end
			});
			//序号亮起的问题
			for (var j = 0; j < spanS.length; j++) {
				spanS[j].className = '';
			}
			this.className = 'active';
			//bug:序号轮播中没有关联 自动轮播中的n变量
			//需要关联一下n变量
			n = this.idx;
		}
	}

动画函数

//缓存动画函数
	function bufferMove(ele, json, fun) { //json是一个用来接收对象的形参
		//json接收的对象形式: {添加动画的属性名:终点值}
		//fun用来接收回调函数
		//让一个元素left移动到指定位置

		//在每次添加定时器之前 先清除一次定时器  防止定时器的叠加
		clearInterval(ele.timer);
		//每一个添加动画效果的元素自己都应该拥有一个自己的定时器,这样才能做到互不影响
		ele.timer = setInterval(function() {
			//为了让所有属性都可以运动到终点 因此这里我们给一个判断标识
			var flag = true; //true表示大家都执行完了
			//循环整个json对象 给每一个属性都添加动画效果
			for (var key in json) { //json:{width:500,height:500,opacity:50}
				var attr = key; //属性名
				var target = json[key]; //终点值
				//1.获取起点
				if (attr == 'opacity') {
					var cur = getStyle(ele, attr) * 100;
				} else {
					var cur = parseInt(getStyle(ele, attr)); //300
				}
				//2.计算步长
				var step = (target - cur) / 10; // 如果步长大于0 要向上取整, 步长小于0 要向下取整
				//3.处理步长
				step = step > 0 ? Math.ceil(step) : Math.floor(step);
				//4.迈出第一只脚  确定下一步的位置
				cur += step;
				//6.在定位之前,判断是否有人没到终点
				if (step > 0 && cur < target) {
					flag = false //证明有人没到终点
				} else if (step < 0 && cur > target) {
					flag = false;
				}
				//5.第二只脚跟上  定位
				if (attr == 'opacity') {
					ele.style[attr] = cur / 100;
				} else {
					ele.style[attr] = cur + 'px';
				}
			}
			//判断 如果大家都到终点了 flag的值为true 否则,值为false
			if (flag == true) {
				//清除定时器
				clearInterval(ele.timer);
				//在动画执行完之后 如果用户传入了 回调函数 我们就调用
				if (fun) {
					fun();
				}
			}
		}, 25)
	}

	function getStyle(ele, attr) {
		if (ele.currentStyle == undefined) { //标准浏览器
			return getComputedStyle(ele)[attr];
		} else { //ie8-
			return ele.currentStyle[attr];
		}
	}
}

js之缓存动画实现轮播图效果_轮播图