本篇博客还是有点难度的,前前后后加起来花了一天时间才算搞明白。涉及的技术栈包括定时器、动画原理、排他思想、json解析、浏览器兼容性问题、根据图片动态显示张数等。关键点是点击上一张和下一张以及特定张时的逻辑实现。
html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>网易轮播图</title>
<link rel="stylesheet" type="text/css" href="css/base.css" target="_blank" rel="external nofollow" />
<script type="text/javascript" src="js/animate.js" ></script>
<script type="text/javascript" src="js/base.js" ></script>
</head>
<body>
<div class="w-slider" id="js_slider">
<div class="slider">
<div class="slider-main" id="slider_main_block">
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/1.jpg" alt="" /></a></div>
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/2.jpg" alt="" /></a></div>
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/3.jpg" alt="" /></a></div>
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/4.jpg" alt="" /></a></div>
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/5.jpg" alt="" /></a></div>
<div class="slider-main-img"><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ><img src="images/6.jpg" alt="" /></a></div>
</div>
</div>
<div class="slider-ctrl" id="slider_ctrl">
<span class="slider-ctrl-prev"></span>
<span class="slider-ctrl-next"></span>
</div>
</div>
</body>
</html>
base.css代码
*{
margin: 0;
padding: 0;
}
img{
/*去除图片地下的空隙*/
vertical-align: top;
}
.w-slider{
width: 310px;
height: 265px;
margin: 100px auto;
position: relative;
overflow: hidden;
}
.slider{
width: 310px;
height: 220px;
}
.slider-main{
width: 620px;
height: 220px;
}
.slider-main-img{
position: absolute;
top: 0;
left: 0;
}
.slider-ctrl{
text-align: center;
padding-top: 5px;
}
.slider-ctrl-con{
width: 24px;
height: 20px;
background:url(../images/icon.png) no-repeat -24px -782px;
display: inline-block;
margin: 0 5px;
cursor: pointer;
/*首行缩进*/
text-indent: -20em;
overflow: hidden;
}
.current{
background-position:-24px -762px ;
}
.slider-ctrl-prev,
.slider-ctrl-next{
position: absolute;
top: 50%;
margin-top: -35px;
width: 20px;
height: 35px;
background: url(../images/icon.png) no-repeat 6px top;
opacity: 0.8;
cursor: pointer;
}
.slider-ctrl-prev{
left: 0;
}
.slider-ctrl-next{
right: 0;
background-position: -14px -44px;
}
animate.js
/**
* Created by ydj on 2018/08/08.
*/
// 多个属性运动框架 添加回调函数
function animate(obj,json,fn) { // 给谁 json
clearInterval(obj.timer);
obj.timer = setInterval(function() {
var flag = true; // 用来判断是否停止定时器 一定写到遍历的外面
for(var attr in json){ // attr 属性 json[attr] 值
//开始遍历 json
// 计算步长 用 target 位置 减去当前的位置 除以 10
// console.log(attr);
var current = 0;
if(attr == "opacity")
{
current = Math.round(parseInt(getStyle(obj,attr)*100)) || 0;
console.log(current);
}
else
{
current = parseInt(getStyle(obj,attr)); // 数值
}
// console.log(current);
// 目标位置就是 属性值
var step = ( json[attr] - current) / 10; // 步长 用目标位置 - 现在的位置 / 10
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//判断透明度
if(attr == "opacity") // 判断用户有没有输入 opacity
{
if("opacity" in obj.style) // 判断 我们浏览器是否支持opacity
{
// obj.style.opacity
obj.style.opacity = (current + step) /100;
}
else
{ // obj.style.filter = alpha(opacity = 30)
obj.style.filter = "alpha(opacity = "+(current + step)* 10+")";
}
}
else if(attr == "zIndex")
{
obj.style.zIndex = json[attr];
}
else
{
obj.style[attr] = current + step + "px" ;
}
if(current != json[attr]) // 只要其中一个不满足条件 就不应该停止定时器 这句一定遍历里面
{
flag = false;
}
}
if(flag) // 用于判断定时器的条件
{
clearInterval(obj.timer);
//alert("ok了");
if(fn) // 很简单 当定时器停止了。 动画就结束了 如果有回调,就应该执行回调
{
fn(); // 函数名 + () 调用函数 执行函数
}
}
},10)
}
function getStyle(obj,attr) { // 谁的 那个属性
if(obj.currentStyle) // ie 等
{
return obj.currentStyle[attr]; // 返回传递过来的某个属性
}
else
{
return window.getComputedStyle(obj,null)[attr]; // w3c 浏览器
}
}
base.js
window.onload = function() {
// 1.获取元素
function $(id) {
return document.getElementById(id);
}
// 2.获取最大的盒子
var js_slider = $("js_slider");
// 3.获取图片组的父类
var slider_main_block = $("slider_main_block");
// 4.获取图片组
var imgs = slider_main_block.children;
// 5.获取控制span的父盒子
var slider_ctrl = $("slider_ctrl");
// 6.动态生成小span
for (var i = 0, len = imgs.length; i < len; i++) {
// 7.创建元素
var span = document.createElement("span");
// 8.为生成的span添加类名,并且倒叙赋值 叠加现象
span.className = "slider-ctrl-con";
span.innerHTML = len - i;
// 9.将生成的span插入到盒子中
slider_ctrl.insertBefore(span, slider_ctrl.children[1]);
}
// 10 为插入的第一个span设置样式
var spans = slider_ctrl.children;
spans[1].setAttribute("class", "slider-ctrl-con current");
// 11.获得后面动画走的距离
var scrollWidth = js_slider.clientWidth;
// 12.开始时只有第一张图片留下,其余的走到显示框的右边
for (var i = 1; i < imgs.length; i++) {
imgs[i].style.left = scrollWidth + "px";
}
// 16.控制图片的张数
var Now = 0;
// 13.开始遍历spans 图片+左右的轮播共计8个
for (var k in spans) {
spans[k].onclick = function() {
// 14.判断当前的span是不是prev
if (this.className == "slider-ctrl-prev") {
//alert("左侧按钮");
// 15.开始动画了 第一个参数 谁要动 第二参数 怎么动 第三个参数 回调函数(可省落)
animate(imgs[Now], {
left: scrollWidth
});
// 17.上一张图片要快速的走到显示框的左侧,然后慢慢的走到舞台中
--Now < 0 ? Now = imgs.length - 1 : Now;
imgs[Now].style.left = -scrollWidth + "px";
animate(imgs[Now], {
left: 0
});
setSquare();
}
// 18.判断当前的按钮时next
else if(this.className=="slider-ctrl-next"){
// 19.当前的图片先慢慢的走到舞台的左边,下一张快速走到舞台的右侧,然后慢慢的走到舞台中
// animate(imgs[Now],{left:-scrollWidth});
// ++Now > imgs.length -1 ?Now =0:Now;
// imgs[Now].style.left = scrollWidth + "px";
// animate(imgs[Now],{left:0});
// setSquare();
autoPlay();
}else{
// 20.点击图片下方的序列 1-2-3-4-5-6 对应图片序号是 0-1-2-3-4-5
var that = this.innerHTML -1;
if(that >Now){
// 21.处理逻辑和next按钮类似 当前的慢慢的走到舞台的左侧,下一张快速走到右侧
animate(imgs[Now],{left:-scrollWidth});
imgs[that].style.left = scrollWidth + "px";
//animate(imgs[that],{left:0});
}else if(that < Now){
// 22 .处理逻辑和prev类似,当前的慢慢走到舞台的右侧,下一张快速走到舞台的左侧
animate(imgs[Now],{left:scrollWidth});
imgs[that].style.left = -scrollWidth + "px";
//animate(imgs[that],{left:0});
}
//else{
Now = that;
animate(imgs[Now],{left:0});
//}
setSquare();
}
}
}
// 设置走动的显示序列
function setSquare(){
// 去掉头部的prev 和尾部的next 两个小span
for(var i = 1,len = spans.length-1;i<len;i++){
spans[i].className = "slider-ctrl-con";
}
// 这里一定要+1 是下一张
spans[Now+1].className = "slider-ctrl-con current";
}
// 设置定时器开始
var timer = null;
timer = setInterval(autoPlay,2000);
// 23 仔细想想其实定时器的运动和设置next这个小span的功能是一样一样的
function autoPlay(){
// 19.当前的图片先慢慢的走到舞台的左边,下一张快速走到舞台的右侧,然后慢慢的走到舞台中
animate(imgs[Now],{left:-scrollWidth});
++Now > imgs.length -1 ?Now =0:Now;
imgs[Now].style.left = scrollWidth + "px";
animate(imgs[Now],{left:0});
setSquare();
}
// 24.鼠标经过清除定时器
js_slider.onmouseover = function(){
clearInterval(timer);
}
// 25.鼠标移开是设置定时器
js_slider.onmouseout = function(){
// 先清除定时器
clearInterval(timer);
// 开启定时器
timer = setInterval(autoPlay,2000);
}
}