为了账号安全,请及时绑定邮箱和手机立即绑定

手风琴效果-原生JS

标签:
JavaScript CSS3

酷炫的手风琴效果

手风琴效果的特点:每次只展开一个元素,其他的兄弟元素都闭合

先从样式和布局开始,做一个原生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. = 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. = 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. = 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. = 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';
            }

        }
    }
})();

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

                      


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消