用狀態機寫輪播

方才的輪播用具體頭腦做,由於不知道它有哪幾種狀況,就一步步來做,等結果做出來后,哪幾種狀況,一覽無餘。下面就用抽象頭腦做一遍.

用抽象頭腦做

初始化CSS款式

*{
    margin:0;
    padding:0;
    box-sizing:border-box;
}
.window{
    width:400px;
    height:300px;
    overflow:hidden;
    margin:20px auto
}
.images{
    position:relative;
}
.images > img{
    position:absolute;
    transition:all 0.5s;
    width:100%;
    top:0;
}

輪播狀況

先來看下這個輪播有那幾種狀況

  1. 圖片出如今視窗狀況,我用 current 示意
  2. 圖片脫離視窗狀況,我用 leave 示意
  3. 圖片預備進入視窗狀況,我用 enter 示意

如今就是要寫三個類,經由過程JS 激活class 來完成輪播

.images > img.current{
    transform:translateX(0);
    z-index:1;
}
.images > img.leave{
    transform:translateX(-100%);
    z-index:1;
}
.images > img.enter{
    transform:translateX(100%);
}

梳理下每張圖片的狀況

  1. 初始化每張圖片的位置,圖片1 出如今當前視窗current,圖片2、圖片3 應當在視窗右側待命,隨時預備進入視窗enter
  2. 當圖片1 脫離視窗時leave,圖片2 進入視窗current
  3. 當上一步悉數完成后,圖片1 應當進入右側待命,等待着進入視窗
  4. 這裏重要相對定位后,會觸發BFC
$('#images > img:nth-child(1)').addClass('current');
$('#images > img:nth-child(2)').addClass('enter');
$('#images > img:nth-child(3)').addClass('enter');

setTimeout(function(){
    $('#images > img:nth-child(1)').removeClass('current').addClass('leave').one('transitionend',function(e){
        $(e.currentTarget).addClass('enter').removeClass('leave')
    });
    $('#images > img:nth-child(2)').removeClass('enter').addClass('current')
},3000);

setTimeout(function(){
    $('#images > img:nth-child(2)').removeClass('current').addClass('leave').one('transitionend',function(e){
        $(e.currentTarget).addClass('enter').removeClass('leave')
    });
    $('#images > img:nth-child(3)').removeClass('enter').addClass('current')
},6000);

setTimeout(function(){
    $('#images > img:nth-child(3)').removeClass('current').addClass('leave').one('transitionend',function(e){
        $(e.currentTarget).addClass('enter').removeClass('leave')
    });
    $('#images > img:nth-child(1)').removeClass('enter').addClass('current')
},9000);

如許一輪輪迴就完畢了,能夠在今後增加setTimeout要領。

無窮輪迴下去

大批反覆的代碼就需要尋覓適宜的的API 替代,一向播下去我們能夠運用DOM APIsetInterval()

$('#images > img:nth-child(1)').addClass('current');
$('#images > img:nth-child(2)').addClass('enter');
$('#images > img:nth-child(3)').addClass('enter');

let n = 1;
setInterval(function(){
    $(`#images > img:nth-child(${x(n)})`).removeClass('current').addClass('leave').one('transitionend',function(e){
        $(e.currentTarget).addClass('enter').removeClass('leave')
    });
    $(`#images > img:nth-child(${x(n+1)})`).removeClass('enter').addClass('current')
    
    n++;    //這裏n 是天然增進,讓它一向玄幻下去
},3000)

//n取值應當是[1,2,3,4,5,...,size]
let allImages = $('#images > img');
let size = allImages.length;
function x(n){
    if(n > size){   //假如n 大於節點size,n就取余
        n = n%size; 
        if(n === 0){    //假如n 取余為0,則讓n即是size
            n = size;
        }
    }
    return n;
}

如許就是完成了無縫輪播,上面用到了ES6的插值法。
在CSS中img:nth-child(n)是沒有這類寫法的,它不能像JS一樣能夠用變量,這邊就用到了ES6 的插值法
`img:nth-child(${n})`\

末了優化下方才寫的代碼

<style>
    *{
        margin:0;
        padding:0;
        box-sizing:border-box;
    }
    .window{
        width:400px;
        height:300px;
        overflow:hidden;
        margin:20px auto
    }
    .images{
        position:relative;
    }
    .images > img{
        position:absolute;
        transition:all 0.5s;
        width:100%;
        top:0;
    }
<style>

<div class="window">
    <div id="images" class="images">
        <img class='png1' src="./images/1.png" width=400 alt="">
        <img class='png2' src="./images/2.png" width=400 alt="">
        <img class='png3' src="./images/3.png" width=400 alt="">
        <img class='png4' src="./images/4.png" width=400 alt="">
        <img class='png5' src="./images/5.png" width=400 alt="">
    </div>
</div>

<script>
    let n = 1;
    int();
    setInterval(function(){
        makeLeave(getImage(n)).one('transitionend',function(e){
            makeEnter($(e.currentTarget))
        });
        makeCurrent(getImage(n+1));
        n++;    //這裏n 是天然增進,讓它一向輪迴下去
    },1000);
    
    //n取值應當是[1,2,3,4,5,...,size]
    let allImages = $('#images > img');
    let size = allImages.length;
    function x(n){
        if(n > size){   //假如n 大於節點size,n就取余
            n = n%size;
            if(n === 0){    //假如n 取余為0,則讓n即是size
                n = size;
            }
        }
        return n;
    }
    
    function getImage(n){
        return $(`#images > img:nth-child(${x(n)})`)
    }
    
    function int(){
        $(`#images > img:nth-child(${n})`).addClass('current').siblings().addClass('enter');
    }
    
    function makeLeave($node){
        return $node.removeClass('current enter').addClass('leave')
    }
    function makeCurrent($node){
        return $node.removeClass('enter leave').addClass('current')
    }
    function makeEnter($node){
        return $node.addClass('enter').removeClass('leave current')
    }
</script>

優化完了以後,現實代碼就只有這麼多,這個被稱為狀況機,如今再看輪播后,腦海里已自動變成了狀況機了。

let n = 1;
int();
setInterval(function(){
    makeLeave(getImage(n)).one('transitionend',function(e){
        makeEnter($(e.currentTarget))
    });
    makeCurrent(getImage(n+1));
    n++;    //這裏n 是天然增進,讓它一向輪迴下去
},1000);

這裏我碰到一個最大的題目之前,是用setTimeout()要領寫的代碼,背面做無窮輪迴時沒想到用setInterval()要領,怎樣調試都不對,這裏看下它們兩個的區分:
setTimeout()要領設置一個定時器,在到時候后實行一段代碼或許函數
setInterval()要領是反覆挪用一段代碼或許函數,每次挪用之間有牢固的時候延時
我們上面寫在setInterval()要領內的函數實在就是一段牢固的代碼,每一個一段時候實行一次,就變成我們看到的輪播了

總結

這一篇的中心是狀況機,把行動變成一個個狀況。用具體化寫出的代碼都是實行的行動,而用抽象化寫出的代碼都是完成后的狀況,代碼構造更清楚,更雅觀。固然要能寫抽象化的代碼,一定少不了具體化的頭腦。

用這類要領最大的優點是行動款式星散,假如我要給變輪播的方向,只需要轉變CSS中的挪動方向即可,還能夠根據需要加上一些酷炫的操縱。

    原文作者:UCCs
    原文地址: https://segmentfault.com/a/1190000014962074
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞