CSS实现超级酷炫的Switch开关,产品直呼: “绝了!”

650 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

前言:

掘友们,大家好,又是我,努力变优秀的前端一枚。今天在CodePen上看到一个开关的demo,源码在:codepen,个人感觉非常酷炫。

目前相对来说,不管是vue项目还是React项目,我们使用的Switch大部分都取于UI框架。比方说Elementantd-vueantd-react、等...,框架内部的UI相对于来说比较简单,但是比较实用。当然,UI框架中的组件样式也是可以修改的。今天小编在CodePen上看到一个开关的demo,浅浅的卷了一下,用在了vue的项目中。

CodePen

开关.gif

在vue项目中使用

下边是小编在码上掘金创建的demo,应用到了vue项目当中,大家可以操作一下。

CSS:

此处小编在项目中使用了scss语法,scss完全兼容所有版本的CSS。需要在项目中安装,安装的时候需要注意版本,

npm i sass-loader@7.3.1 -D 
npm i node-sass@4.14.1 -D
* {
  margin: 0;
  padding: 0;
}
html {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  body {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    #box {
      width: 100%;
      height: 100%;
      background-color: #cccccc;
      display: flex;
      justify-content: space-around;
      align-items: center;
      box-sizing: border-box;
      padding: 20px;
      .switch {
        width: 350px;
        height: 200px;
        .item {
          width: 100%;
          height: 70px;
          background-color: #000;
          border-radius: 90px;
          font-size: 20px;
          padding: 20px 30px;
          box-sizing: border-box;
          position: relative;
          .bg {
            box-sizing: border-box;
            width: 130px;
            height: 40px;
            border-radius: 80px;
            background-color: #fff;
            position: absolute;
            top: 15px;
            right: 20px;
            transition: width 0.4s;
          }
          .text1 {
            color: #fff;
            font-weight: 800;
            position: absolute;
            top: 20px;
            left: 30px;
          }
          .text2 {
            color: #000;
            font-weight: 800;
            position: absolute;
            top: 20px;
            right: 30px;
          }
        }
        .item2 {
          overflow: hidden;
          margin-top: 20px;
          width: 100%;
          height: 70px;
          background-color: #000;
          border-radius: 90px;
          font-size: 20px;
          padding: 20px 30px;
          box-sizing: border-box;
          position: relative;
          #ONLeft {
            position: absolute;
            top: 0;
            left: 0;
            transform: translate(-100%);
            width: 100%;
            height: 100%;
            border-radius: 90px;
            background-color: #000;
            transition: all 1s;
          }
          #OFFRight {
            position: absolute;
            top: 0;
            right: 0;
            transform: translate(100%);
            width: 100%;
            height: 100%;
            border-radius: 90px;
            background-color: #fff;
            transition: all 1s;
          }
          .text1 {
            color: #000;
            font-weight: 800;
            position: absolute;
            top: 20px;
            left: 30px;
            z-index: 10;
          }
          .text2 {
            color: #fff;
            font-weight: 800;
            position: absolute;
            top: 20px;
            right: 30px;
            z-index: 10;
          }
        }
      }
    }
  }
}

HTML:

vue2

<template>
  <div id="box">
    <div class="switch">
      <div class="item" id="switchitem" @click="click">
        <div class="bg" id="switchbg"></div>
        <div class="text1">ON</div>
        <div class="text2">OFF</div>
      </div>
      <div class="item2" id="switchitem2" @click="clickstate">
        <div class="text1">ON</div>
        <div class="text2">OFF</div>
        <div id="ONLeft">
            <div class="text1">ON</div>
        </div>
        <div id="OFFRight">
            <div class="text2">OFF</div>
        </div>
      </div>
    </div>
  </div>
</template>

JS:

通过JS事件操作元素的样式,声明状态类型,查看是否打开开关。addEventListene为元素添加transitionend动画结束事件。在动画结束后,让开关恢复状态,用于下一次打开或者关闭。

export default {
  name: "switch",
  components: {},
  data() {
    return {
      states: false,
      state: false,
    };
  },
  methods: {
    click() {
      var switchbg = document.getElementById("switchbg");
      var switchitem = document.getElementById("switchitem");
      this.states = !this.states;
      if (this.states) {
        switchbg.style.backgroundColor = "#000";
        switchitem.style.backgroundColor = "#fff";
      } else {
        switchbg.style.backgroundColor = "#fff";
        switchitem.style.backgroundColor = "#000";
      }
      switchbg.addEventListener("transitionend", this.handle, false);
      switchbg.style.width = 310 + "px";
    },
    handle() {
      var switchbg = document.getElementById("switchbg");
      if (this.states) {
        switchbg.style.left = 20 + "px";
        switchbg.style.right = null;
        switchbg.style.width = 100 + "px";
      } else {
        switchbg.style.left = null;
        switchbg.style.right = 20 + "px";
        switchbg.style.width = 100 + "px";
      }
    },
    clickstate() {
      this.state = !this.state;
      var switchitem2 = document.getElementById("switchitem2");
      var OFFRight = document.getElementById("OFFRight");
      var ONLeft = document.getElementById("ONLeft");
      if (this.state) {
        switchitem2.style.backgroundColor = '#000'
        OFFRight.style.transform = "translate(0)";
        ONLeft.style.transform = "translate(-100%)";
      } else {
          switchitem2.style.backgroundColor = '#fff'
        OFFRight.style.transform = "translate(100%)";
        ONLeft.style.transform = "translate(0)";
      }
    },
  },
};

总结

Switch开关可以随意设置样式属性,方法不一,关于CodePen中的demo,小编并没有按照作者的方法只操作css控制开关。在项目的实际开发过程中,我们是要知道Switch开关的状态,从而做一些其他的判断,所以,小编通过js控制盒子的样式,通过transform和transition来达到动画的效果,方法可能有点笨重,但是还是按照自己的想法做出来了。希望对大家有用