使用JS实现Element-UI的Collapse(手风琴和折叠面板)组件

2,564 阅读4分钟

Collapse组件

在开始之前,我还是先放上最终的实现效果 手风琴和折叠面板 HTML结构

<div class="container">
        <div class="collapse">
            <h2>Collapse折叠面板</h2>
            <div class="item">
                <div class="item-header">一致性 Consistency</div>
                <div class="item-content">
                    与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;<br>
                    在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div>
            </div>
            <div class="item active">
                <div class="item-header">反馈 Feedback</div>
                <div class="item-content">控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;<br>
                    页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。</div>
            </div>
            <div class="item">
                <div class="item-header">效率 Efficiency</div>
                <div class="item-content">简化流程:设计简洁直观的操作流程;<br>
                    清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;<br>
                    帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担</div>
            </div>
            <div class="item">
                <div class="item-header">可控 Controllability</div>
                <div class="item-content">用户决策:根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;<br>
                    结果可控:用户可以自由的进行操作,包括撤销、回退和终止当前操作等。</div>
            </div>
        </div>
    </div>

CSS我先放一部分

.container {
    max-width: 800px;
    border-radius: 4px;
    box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.3);
    padding: 16px;
    margin: 30px auto;
}
.collapse {
    font-size: 13px;
}
.collapse .item {
    border-top: 1px solid #ddd;
    cursor: pointer;
}
.collapse .item:last-child {
    border-bottom: 1px solid #ddd;
}
.collapse .item:last-child {
    border-bottom: 1px solid #ddd;
}
.item .item-header {
    display: flex;
    align-items: center;
    font-size: 14px;
    font-weight: 600;
    line-height: 4;
    color: #303030;
}

上面的代码实现了基本的页面结构和CSS,接下来使用JS实现最终的效果,这里跟上一篇文章不同,上一篇使用的是面向过程的思想,这里我使用面向的对象方式,如有不懂的,请Google两者之间的区别。创建一个class类为Collapse,并给constructor加一个参数为container,通过container,通过container获取对应的item,并绑定一个bind方法。并在下方写好对应的调用实例。

class Collapse{
    constructor($container,type=1){
        this.$container = $container
        this.$$items =  $container.querySelectorAll('.item')
        this.bind()
    }
}
new Collapse(document.querySelector('.collapse'))

现在实现bind方法,还是一样的思路循环其中的每一个item,点击其中一个的item,把active添加到被点击的item上,删除其他item上active,具体实现如下

bind(){
    let self = this
    this.$$items.forEach($items => {
        $items.onclick = function(){ self.$$items.forEach($items=>$items.classList.remove('active'))
        this.classList.add('active')
        }
    });
}

需要注意的是,这里并不能一直使用this,当点击item时this的指向变为了Window,不信的话,可以做一个测试,将里面的self变为this,所以需要使用一个变量暂时将this保存起来,防止this变为Window。初步来看,Collapse算是完成了。这个时候如果需要一个手风琴的效果,我们需要将代码重写一边吗?当然不是,手风琴的效果和折叠面板的效果类似,唯一不同的是多了一个第一次点击自身的item展开,第二次点击item折叠起来就ok了,有了这个思路,就可以同时实现手风琴和折叠面板的效果,在constructor中需要加一个参数为type默认为1(1为手风琴的效果),通过判断type是1或者2来区分是手风琴和折叠面板。然后通过js中的toogle()方法实现item的隐藏和展现。具体实现如下

constructor(type=1){
	this.type = type
}
if(self.type === 2 ){
this.classList.toggle('active')
}else if(self.type === 1){
self.$$items.forEach($items=>$items.classList.remove('active'))
this.classList.add('active')
}

大致完成了Collapse的效果,如果这个时候页面上有两个container容器,一个是折叠面版,一个是手风琴,如何启动它们?很简单,通过querySelectorAll('.collapse')方法获取对应手风琴或者折叠面板的下标就能够启动,并标注所对应的type类型就能够实现,具体实现如下

new Collapse(document.querySelectorAll('.collapse')[0])
new Collapse(document.querySelectorAll('.collapse')[1],2)

目前为止,Collpase基本实现了,还有一个东西未实现,item右边有一个三角形,点击item展示内容,三角形也跟着旋转。这个就比较简单了,使用.item-header::after伪元素创建一个颜色为黑色的三角形,.item-header上使用flex布局,并让三角形靠在最右边,当我们点击item时,三角形也会跟着旋转就行了,具体实现如下。

.item .item-header {
    display: flex;
    align-items: center;
    font-size: 14px;
    font-weight: 600;
    line-height: 4;
    color: #303030;
}
.item .item-header::after {
    content: '';
    display: block;
    width: 6px;
    height: 6px;
    border-top: 1px solid #303030;
    border-right: 1px solid #303030;
    margin-left: auto;
    transform: rotate(45deg);
}
.item.active .item-header::after {
    transform: rotate(135deg);
    transition: all .3s;
}
.item .item-content {
    font-size: 14px;
    color: #666;
    height: 0;
    overflow: hidden;
}
.item.active .item-content {
    height: auto;
    padding-bottom: 30px;
    transition: all .3s;
}

到此为止,Collapse组件创建完成