效果
思路
使用checkbox
来实现,勾选、未勾选对应开启、关闭状态,使用:checked
选择器来控制开启状态下的样式显示。
关键
怎样修改checkbox
的原始样式?
appearance
的用武之地(MDN链接),appearance
英译外观、外貌
,作用改变元素的UI
。在MDN上我们可以看到有很多的属性值,注意到checkbox复选框
的appearance
属性值默认就是checkbox
,所以我们将这个元素属性重置为none
后,当做普通元素通过CSS
来实现我们的开关效果,注意前缀。
实现代码
<!DOCTYPE html>
<html>
<head>
<title>switch开关实现</title>
<style type="text/css">
.switch {
width: 57px;
height: 28px;
position: relative;
border: 1px solid #dfdfdf;
background-color: #DCDFE6;
box-shadow: #dfdfdf 0 0 0 0 inset;
border-radius: 20px;
background-clip: content-box;
display: inline-block;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
user-select: none;
outline: none;
}
.switch::before {
content: '';
position: absolute;
width: 22px;
height: 22px;
background-color: #FFFFFF;
border-radius: 50%;
left: 2px;
top: 0;
bottom: 0;
margin: auto;
transition: .3s;
}
.switch:checked {
background-color: #409EFF;
transition: .6s;
}
.switch:checked::before {
left: 30px;
transition: .3s;
}
</style>
</head>
<body>
<input type="checkbox" class="switch" checked />
</body>
</html>
升级版
上面只是简单实现了switch
的开关效果,我们一般需要使用到switch
的地方,肯定都是需要请求后台去实现数据状态改变的,那上面实现的弊端显而易见,我只要点击了开关,开关就闭合或打开,完全不会等到请求成功之后再进行闭合或打开,如果我们在请求失败的情况下再进行开关的重置操作,那这种交互肯定是不能满足产品经理滴。
我们需要的是只有在请求成功后才让开关去闭合或打开,笔者是vue
的使用者,可以看到在vue2.0
下使用最多的ElementUI
库也不能实现这个效果,所以如果实在需要,那我们就自己动手呗。为了实现这个效果,我们需要放弃使用checked
选择器,因为这会带来问题:checked
选择器依赖复选框的默认行为,而又不能一句event.preventDefault()
阻止默认行为,所以下面我的代码是这样写的:
<!DOCTYPE html>
<html>
<head>
<title>switch开关实现</title>
<style type="text/css">
.switch {
width: 57px;
height: 28px;
position: relative;
border: 1px solid #dfdfdf;
background-color: #DCDFE6;
box-shadow: #dfdfdf 0 0 0 0 inset;
border-radius: 20px;
background-clip: content-box;
display: inline-block;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
user-select: none;
outline: none;
}
.switch::before {
content: '';
position: absolute;
width: 22px;
height: 22px;
background-color: #FFFFFF;
border-radius: 50%;
top: 0;
bottom: 0;
margin: auto;
}
.switch_uncheck::before {
left: 2px;
transition: .3s;
}
.switch_check {
background-color: #409EFF;
transition: .6s;
}
.switch_check::before {
left: 30px;
transition: .3s;
}
</style>
</head>
<body>
<input type="checkbox" class="switch switch_uncheck" onclick="clickHandle(event)" />
<script type="text/javascript">
// 定义switch开关的初始状态,默认关闭
let status = false
function clickHandle(event) {
let switchs = document.querySelector('.switch')
setTimeout(() => {
// TODO 这里进行请求操作,成功时改变status,失败时不改变
status = !status
if (status) {
switchs.classList.add('switch_check')
switchs.classList.remove('switch_uncheck')
} else {
switchs.classList.remove('switch_check')
switchs.classList.add('switch_uncheck')
}
}, 1000)
}
</script>
</body>
</html>
效果
可以看到点击后会有1s
的延迟效果才闭合或打开,我使用setTimeout
只是模拟操作过程。当然我们一般肯定是需要进行封装组件的操作的,封装组件的时候,使其可以接收一个函数,组件内部进行promise
封装,然后根据请求的成功与否再决定开关是否打开或保持不动。这里只提供思路,具体的组件封装我以后会在自己的vue3.0官网demo中去实现。