menu search

网页版三选二

Aug 12, 2017

早上在Twitter上看见了这个GIF,想了想实现起来应该也不难,就打算用前端技术做一个类似的。

简单的来说其实就是<input type="checkbox"><label>。我们无法直接修改HTML复选框的的样式,但如果使用一个<label>标签即可做到。

之所以用<label>而不是其他标签的原因是因为在给它加上了for属性后,点击它就可以更改复选框的状态。同时,label标签也支持使用伪元素。(Input属于自闭合标签,不能添加伪元素)


HTML

<div>
    <input type="checkbox" id="first" />
    <label for="first"></label>
    <span>Work</span>
</div>

<div>
    <input type="checkbox" id="second" />
    <label for="second"></label>
    <span>Social Life</span>
</div>

<div>
    <input type="checkbox" id="third" />
    <label for="third"></label>
    <span>Sleep</span>
</div>

<div>标签分开了每组复选框,<span>用来显示文字。

CSS

body{
    display: flex;
    display: -webkit-flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    height: 100vh;
}
div {
    display: flex;
    display: -webkit-flex;
    margin-bottom: 10px;
    align-items: center;
}

input[type=checkbox] {
    display: none;
}

label {
    background: #ecf0f1;
    height: 40px;
    width: 80px;
    display: block;
    border-radius: 1000000em;
    position: relative;
    cursor: pointer;
    transition: background .3s ease;
    &:after {
        content: "";
        height: 30px;
        width: 30px;
        position: absolute;
        top: 5px;
        left: 5px;
        background: #fff;
        border-radius: 100%;
        border: 2px solid #fff;
        box-sizing: border-box;
        box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
        transition: all .3s ease;
    }
}

input[type=checkbox]:checked + label{
    background: #f39c12;
    &:after {
        left: calc(100% - 35px);
    }
}

span {
    margin-left: 15px;
}

<div>加了Flexbox的属性(我发现我现在干什么都喜欢用这个),主要是为了可以方便的水平居中元素。

<input>可以直接隐藏掉,不显示出来照样可以选中。

<label>在这里是最重要的,负责替代复选框,并输出样式。我使用了:after来做圆形按钮,主要是为了不过多添加标签。

CSS 里面很重要的一句是 input[type=checkbox]:checked + label:当复选框被选中,临近的<label>的样式将会被修改。

Javascript

let checked = [];

[...document.querySelectorAll('input[type=checkbox]')].forEach((checkbox, i) => {
    checkbox.addEventListener('change', (e) => {
        if (checkbox.checked) {
            checked.push(e.target);
        }
        else{
            let index = checked.indexOf(e.target);
            checked.splice(index, 1);
        };
    
        if (checked.length > 2) {
            checked[0].checked = false;
            checked.splice(0, 1);
        };
    });
});

最后,为了达到只能选择两个复选框的效果似乎只能使用JS,我没找到可以限制数量的属性。不过也没关系,脚本很短。

首先,定义一个checked数组,然后给所有的复选框绑定change事件。change事件会在选中/取消时被触发,可以通过e.target.checked来判断状态。如果是选中状态,就往checked数组添加这个复选框。

接着得判断被选中的数量,可以直接判断数组的大小,并把处于数组第一位的复选框 (也就是第一个被选中的) 移除,并取消选中。

最终结果

三选二


Extra

尝试实现了下这张图片的效果:

如何选择VPS

Comments

edit x send markdown image
paragraph comment heart