天天看点

手风琴效果——原生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写在前面酷炫的手风琴效果

写完结构和样式,对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';
            }

        }
    }
})();
           

此时,测试没有问题,接下来给代码添加动画,回到第一步

继续阅读