1. 程式人生 > 其它 >案例——輪播圖(原生JS實現)

案例——輪播圖(原生JS實現)

技術標籤:JavaScriptjavascript

效果圖
在這裡插入圖片描述
首先我們來理一下思路

  • 搭建結構

    注意點:
    我們需要一個container輪播圖容器,溢位隱藏
    我們需要一個wrapper容器用於存放所有的圖片,wrapper相對於container定位,後期改變wrapper的left值實現輪播圖的切換

  • 寫樣式…

  • 寫js

  1. 獲取所有需要操作的元素
  2. 獲取資料(基於AJAX非同步獲取資料,當然沒有伺服器提供資料,只能自己寫一點)
  3. 實現資料繫結HTML頁面(基於Promise管理非同步操作)
    注意繫結的時候圖片要多繫結一個,便於後面實現無縫輪播
  4. (每隔interval秒,實現單張輪播圖的自動運動和切換)
  5. 實現輪播圖的自動運動和切換
    - 設定輪播圖運動的基礎引數(全域性變數)stepIndex,autoTimer,interval
    - 開啟定時器驅動自動輪播(實現每隔interval秒輪播圖的自動運動和切換)
    - stepIndex++(圖片要切換了,當前圖片索引改變)
    - 當索引大於原來的長度,讓其立即運動到第一張,再讓其運動第二張(最後一張圖片和第一張圖片一摸一樣,立即運動表示直接設定它的left屬性,讓它在運動最後一張圖片的時候切換到第一張圖片,人眼是看不出來的跳轉的,這樣可以實現無縫銜接)
    - 設定動畫(讓圖片在1秒內完成切換)
    - 切換焦點
  6. 實現滑鼠進入和離開自動輪播的停止和開啟,和按鈕的隱藏和顯示
  7. 實現點選焦點時圖片的切換
  8. 實現點選按鈕時圖片的切換

然後直接上程式碼!!!
html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>輪播圖</title>
    <link rel="stylesheet/less"
href="css/banner.less">
<script src="js/less.min.js"></script> </head> <body> <section class="container" id="container"> <div class="wrapper"> <!-- <div><img src="img/1.png" alt=""></div> <div><img src="img/2.png" alt=""></div> <div><img src="img/3.png" alt=""></div> <div><img src="img/4.png" alt=""></div> --> </div> <ul class="focus"> <!-- <li class="active"></li> <li></li> <li></li> <li></li> --> </ul> <a href="javascropt:;" class="arrow arrowLeft"></a> <a href="javascropt:;" class="arrow arrowRight"></a> </section> <script src="js/utils.js"></script> <script src="js/animate.js"></script> <script src="js/banner.js"></script> </body> </html>

css

@import "baseCss";
.container{
    position: relative;
    margin: 20px auto;
    width: 1000px;
    height: 300px;
    overflow: hidden;
    .wrapper{
        position: absolute;
        left: 0;
        top: 0;
        width: 4000px;
        height: 100%;
        div{
            float: left;
            width: 1000px;
            height: 100%;
            img{
                width: 100%;
                height: 100%;
            }
        }
    }
    .focus{
        position: absolute;
        left: 50%;
        bottom: 10px;
        transform: translateX(-50%);
        height: 12px;
        border-radius: 6px;
        background: rgba(0, 0, 0, .5);
        li{
            float: left;
            margin: 3px;
            width: 6px;
            height: 6px;
            background: #fff;
            border-radius: 50%;
            &.active{
                background: lightseagreen;
            }
        }

    }
    .arrow{
        position: absolute;
        
        display: none;
        width: 41px;
        height: 69px;
        &.arrowLeft{
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            background: url(../img/icon-slides.png) no-repeat -84px 0;

            &:hover{
                background: url(../img/icon-slides.png) no-repeat 0 0;

            }
        }
        &.arrowRight{
            right: 0;
            top: 50%;
            transform: translateY(-50%);
            background: url(../img/icon-slides.png) no-repeat -126px 0;

            &:hover{
                background: url(../img/icon-slides.png) no-repeat -42px 0;

            }
        }
    }
}

js

let bannerRender = (function() {
    //1. 獲取操作的的元素
    let container = document.querySelector('#container'),
        wrapper = container.querySelector('.wrapper'),
        focus = container.querySelector('.focus'),
        arrowLeft = container.querySelector('.arrowLeft'),
        arrowRight = container.querySelector('.arrowRight'),
        slideList = null,
        focusList = null;

    //輪播圖運動的基礎引數
    let stepIndex = 0, //記錄當前展示快的索引
        autoTimer = null, //自動輪播的定時器
        interval = 3000; //間隔多長時間自動切換

    //2. 獲取資料
    let queryData = function() {
        return new Promise((resolve, reject) => {
            let xhr = new XMLHttpRequest();
            xhr.open('get', 'json/banner.json', true); //非同步獲取資料
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    let data = JSON.parse(xhr.responseText);
                    resolve(data);
                }
            };
            xhr.send(null);
        });
    };
    //3. 實現資料繫結(獲取資料成功之後執行資料繫結方法)
    let bindHTML = function(res) {

        let strSlide = ``,
            strFocus = ``;
        res.forEach((item, index) => {
            let {
                id,
                img = 'img/1.png',
                desc = 'xiaomi',
                link
            } = item;
            strSlide += `<div><img src="${img}" alt="${desc}"></div>`;
            //ES6模板字串${}存放的是JS表示式,但是表示式要有返回值,因為我們要把返回值拼接到模板字串中
            strFocus += `<li class="${index === 0?'active':''}"></li>`
        });
        //克隆一份到末尾
        strSlide += `<div><img src="${res[0].img}" alt="${res[0].desc}"></div>`;
        wrapper.innerHTML += strSlide;
        focus.innerHTML += strFocus;

        slideList = wrapper.querySelectorAll('.wrapper > div');
        focusList = focus.querySelectorAll('.focus > li');
        //根據slide的個數動態計算wrapper的寬度
        utils.setCss(wrapper, 'width', slideList.length * 1000);
    };
    //改變焦點
    let changeFocus = function() {
        let tempIndex = stepIndex; //建立臨時索引
        tempIndex === slideList.length - 1 ? tempIndex = 0 : null;
        [].forEach.call(focusList, (item, index) => {
            item.className = index === tempIndex ? 'active' : '';
        });
    };
    //4. 實現輪播圖的運動和切換
    //輪播圖無縫銜接原理:
    //- 克隆第一張到末尾(在資料繫結的時候克隆)
    //- 正常累加運動,當運動到末尾(此時的末尾是克隆的哪一張),再過3秒切換的時候,後面就沒有圖片了,此時我們讓其立即切換到真實第一張的位置
    // (立即切換,沒有動畫,left=0,剛才展示的最後一張和真實的第一張長的一樣,給使用者感覺沒有切換),緊接著運動到第二張即可
    let autoMove = function() {

        stepIndex++;
        //如果索引大於原來的長度,讓其瞬間運動到第一張,再讓其運動到第二張
        if (stepIndex > (slideList.length - 1)) {
            utils.setCss(wrapper, 'left', 0);
            stepIndex = 1; //不是等於0,而是等於1,這樣可以切換到第二張
        }
        //基於自己封裝的animate實現動畫
        animate(wrapper, {
            left: -stepIndex * 1000
        }, 1000);

        //每一次運動完成,需要讓焦點跟著切換
        changeFocus();

    };

    //5. 實現滑鼠進入和離開控制自動輪播的停止和開啟
    let handleContainer = function() {
        container.onmouseenter = function() {
            clearInterval(autoTimer);
            arrowLeft.style.display = arrowRight.style.display = 'block';
        };
        container.onmouseleave = function() {
            autoTimer = setInterval(autoMove, interval);
            arrowLeft.style.display = arrowRight.style.display = 'none';
        };
    };
    //6. 實現點選焦點圖片切換
    let handleFocus = function() {
        [].forEach.call(focusList, (item, index) => {
            item.onclick = function() {
                stepIndex = index;
                animate(wrapper, {
                    left: -stepIndex * 1000
                }, 1000);
                changeFocus();
            };
        });
    };
    //7. 實現點選按鈕圖片
    let handleArrow = function() {
        arrowRight.onclick = autoMove;
        arrowLeft.onclick = function() {
            stepIndex--;
            //如果索引小於零,則是第一張,不能再向右運動了,此時因當瞬間運動到最後一張(和第一張一模一樣),再讓其運動到倒數第二張
            if (stepIndex < 0) {
                utils.setCss(wrapper, 'left', -(slideList.length - 1) * 1000);
                stepIndex = slideList.length - 2;
            }
            animate(wrapper, {
                left: -stepIndex * 1000
            }, 1000);
            changeFocus();
        };
    }
    return {
        init: function() {
            let promise = queryData();
            promise.then(res => {
                bindHTML(res);
            }).then(() => {
                //開啟定時器驅動的自動輪播
                autoTimer = setInterval(autoMove, interval);
            }).then(() => {
                //左右按鈕或者焦點切換
                handleContainer();
                handleFocus();
            	handleArrow();
            });
        }
    };
})();
bannerRender.init();