switch开关实现

2,551

效果

思路

使用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中去实现。