天天看点

仿网易轮播图(html+css+javascript)

本篇博客还是有点难度的,前前后后加起来花了一天时间才算搞明白。涉及的技术栈包括定时器、动画原理、排他思想、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);
	}
}
           

继续阅读