本篇部落格還是有點難度的,前前後後加起來花了一天時間才算搞明白。涉及的技術棧包括定時器、動畫原理、排他思想、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);
}
}