1. 程式人生 > >手風琴效果——原生JS

手風琴效果——原生JS

寫在前面

作為一隻前端小汪,以自己一個初學者的視角,在這裡記錄自己在學習過程中遇到的問題,解決的方法,也算是成長的歷程吧!過程中難免會有疏忽和自己沒有發現的錯誤,如果你碰巧看到了我的部落格,歡迎和我一起交流、學習,給我提出寶貴的意見。

我的QQ群號:495086635,需要學習資源的歡迎進群,我自己的資源無償提供給大家。

酷炫的手風琴效果

手風琴效果的特點:每次只展開一個元素,其他的兄弟元素都閉合

先從樣式和佈局開始,做一個原生JS的手風琴效果

html:

<div class="c">
    <p class="red">1</p>
    <p class="blue">2</p>
    <p class="green">3</p>
    <p class="yellow">4</p>
</div>

 css:

.c{
    background-color: black;
}
.c::before,.c::after{
    content: '';
    display: table;
}
.c::after{
    clear: both;
}
.red{
    width: 100px;
    background-color:red;
    float: left;
    height: 300px;
}

.blue{
    background-color:blue;
}
.green{
    background-color: green;
}
.yellow{
    background-color: yellow;
}
.yellow,.green,.blue{
    width: 20px;
    float: left;
    height: 300px;
}

效果如圖:

寫完結構和樣式,對JS要完成的效果進行拆解

需求分析:當滑鼠點選一個元素時,對應元素的寬度變大,兄弟元素中寬度最大的元素寬度變小

實踐:

1.首先,手風琴的效果要動起來,在JS中能夠動起來的只有計時器,因此這裡會用到週期性計時器,這一步可以後寫,先進行第二步

如果你回到這裡,恭喜你,已經完成了一半

問題:何時停掉計時器,停計時器要寫在計時器函式中,滿足條件時清除計時器

+(function () {
    //查詢元素
    var c = document.querySelector('.c');
    var ps = document.querySelectorAll('.c p');

    //繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
    for (var i = 0; i < ps.length; i++) {

        //需求的第一個元素:被點選的元素
        var p = ps[i];


        p.onclick = function () {
            //需求的第二個元素:兄弟中最大的元素
            for (var j = 0; j < ps.length; j++) {
                if(getComputedStyle(ps[j]).width=='100px'){
                    var obj = ps[j];
                    break;
                }
            }

            if(parseInt(getComputedStyle(this).width)==20){

                //新增計時器
                var timer = setInterval(move,100);
                var step = 10;
                var that = this;
                function move() {
                    if(parseInt(getComputedStyle(that).width)<100){
                        //點選的當前元素寬度變大
                        that.style.width = parseInt(getComputedStyle(that).width) + step + 'px';
                        obj.style.width = parseInt(getComputedStyle(obj).width) - step + 'px';
                        console.log(getComputedStyle(that).width);
                    }else{
                        clearInterval(timer);
                    }

                }

            }

        }
    }
})();

問題:如果一次元素的寬度尚未到達20px,又去點選另一個元素,這時兩個元素會同時動,

解決:讓一個動作完成再執行另一個動作

分析:判斷另一個動作是否要執行時在執行前判斷的,所以在事件之外定義一個布林全域性變數

+(function () {
    //查詢元素
    var c = document.querySelector('.c');
    var ps = document.querySelectorAll('.c p');

    //繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
    for (var i = 0; i < ps.length; i++) {

        //需求的第一個元素:被點選的元素
        var p = ps[i];
        var flag = true;

        p.onclick = function () {
            if(flag){
                flag = false;
                //需求的第二個元素:兄弟中最大的元素
                for (var j = 0; j < ps.length; j++) {
                    if(getComputedStyle(ps[j]).width=='100px'){
                        var obj = ps[j];
                        break;
                    }
                }

                if(parseInt(getComputedStyle(this).width)==20){

                    //新增計時器
                    var timer = setInterval(move,100);
                    var step = 10;
                    var that = this;
                    function move() {
                        if(parseInt(getComputedStyle(that).width)<100){
                            //點選的當前元素寬度變大
                            that.style.width = parseInt(getComputedStyle(that).width) + step + 'px';
                            obj.style.width = parseInt(getComputedStyle(obj).width) - step + 'px';
                            console.log(getComputedStyle(that).width);
                        }else{
                            clearInterval(timer);
                            flag = true;
                        }

                    }

                }
            }
        }
    }
})();

2.從需求來看,這裡需要一個事件,事件的三要素:元素、事件、函式

元素:被點選的元素和兄弟元素中最大的那個(兩個)

事件:click

函式:匿名函式

函式的功能:①點選的當前元素:如果寬度為20px,變為100px;否則,不變

+(function () {
    //查詢元素
    var c = document.querySelector('.c');
    var ps = document.querySelectorAll('.c p');

    //繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
    for (var i = 0; i < ps.length; i++) {

        //需求的第一個元素:被點選的元素
        var p = ps[i];
        //需求的第二個元素:兄弟中最大的元素
        for (var j = 0; j < ps.length; j++) {
            if(getComputedStyle(ps[j]).width=='100px'){
                var obj = ps[j];
                break;
            }
        }
        
        p.onclick = function () {
            console.log("我執行了");
            //點選的當前元素寬度變大
            if(getComputedStyle(this).width=='20px'){
                this.style.width = 100 + 'px';
                obj.style.width = 20 + 'px';
            }

        }
    }
})();

程式碼到這裡遇到一個問題:除了初始設定預設值100px的那個元素,以後的元素寬度都不會再變回20px

分析:兄弟中最大的元素除了預設值之外,都是點選事件發生後才產生的,上面的程式碼只在初始時獲得一次,點選後產生的最大兄弟元素並沒有獲得,因此,查詢兄弟中最大的元素應該放在事件處理函式中

更新程式碼:

+(function () {
    //查詢元素
    var c = document.querySelector('.c');
    var ps = document.querySelectorAll('.c p');

    //繫結事件:事件的物件是其中一個p元素,給每個p元素繫結事件
    for (var i = 0; i < ps.length; i++) {

        //需求的第一個元素:被點選的元素
        var p = ps[i];


        p.onclick = function () {
            //需求的第二個元素:兄弟中最大的元素
            for (var j = 0; j < ps.length; j++) {
                if(getComputedStyle(ps[j]).width=='100px'){
                    var obj = ps[j];
                    break;
                }
            }
            
            //點選的當前元素寬度變大
            if(getComputedStyle(this).width=='20px'){
                this.style.width = 100 + 'px';
                obj.style.width = 20 + 'px';
            }

        }
    }
})();

此時,測試沒有問題,接下來給程式碼新增動畫,回到第一步