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获取对应的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组件创建完成