封装一个开关组件

833 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

TIP 👉 江山代有才人出,各领风骚数百年。清·赵翼《论诗》

前言

在我们日常项目开发中,我们经常会做一些功能的开关控制,所以封装了这款开关组件。

开关组件

属性

1. value
  • 是否打开
  • 值为布尔类型
  • 默认为:false
2. disabled
  • 是否不可用
  • 值为布尔类型
  • 默认为:false
3. showText
  • 是否显示字,“开”或者“关”
  • 值为布尔类型
  • 默认为:true

事件

1. change 值改变事件
  • 参数:value 是否打开(值为布尔类型)

示例

template:

<div class="switch-list">
  <div class="item">
    <span>开启系统通知</span>
    <BaseSwitch v-model="isOpen1" @change="doChange"></BaseSwitch>
  </div>
  <div class="item">
    <span>开启短息提醒</span>
    <BaseSwitch v-model="isOpen2" @change="doChange"></BaseSwitch>
  </div>
  <div class="item">
    <span>不显示字:关</span>
    <BaseSwitch v-model="isOpen3" :showText="false" @change="doChange"></BaseSwitch>
  </div>
  <div class="item">
    <span>不显示字:开</span>
    <BaseSwitch v-model="isOpen4" :showText="false" @change="doChange"></BaseSwitch>
  </div>
  <div class="item">
    <span>不可用:关</span>
    <BaseSwitch v-model="isOpen5" :disabled="true" @change="doChange"></BaseSwitch>
  </div>
  <div class="item">
    <span>不可用:开</span>
    <BaseSwitch v-model="isOpen6" :disabled="true" @change="doChange"></BaseSwitch>
  </div>
</div>

js:

import BaseSwitch from '@/components/base/switch/index.vue'
export default {
  name: 'SwitchDemo',
  components: {
    BaseSwitch
  },
  data () {
    return {
      isOpen1: false,
      isOpen2: true,
      isOpen3: false,
      isOpen4: true,
      isOpen5: false,
      isOpen6: true
    }
  },
  methods: {
    doChange (val) {
      console.log('触发change事件,value = ', val)
    }
  }
}

switch.vue

<template>
  <div class="switch-bar" :class="statusClass" @click="doSwitch">
    <span v-if="showText" class="text">{{currentValue?'开':'关'}}</span><div class="switch-handle"></div>
  </div>
</template>
<script>
export default {
  name: 'BaseSwitch',
  props: {
    value: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    showText: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      currentValue: this.value
    }
  },
  computed: {
    statusClass () {
      let statusClass = []
      if (this.currentValue) {
        statusClass.push('on')
      }
      if (this.disabled) {
        statusClass.push('disabled')
      }
      if (this.currentValue && this.disabled) {
        statusClass.push('disabled-on')
      }
      return statusClass
    }
  },
  watch: {
    value (val) {
      this.currentValue = val
    }
  },
  methods: {
    doSwitch () {
      if (!this.disabled) {
        this.currentValue = !this.currentValue
        this.$emit('input', this.currentValue)
        this.$emit('change', this.currentValue)
      }
    }
  }
}
</script>
<style lang="scss" scoped px2rem="false">
$bar-width: 48px;
$bar-height: 24px;
$bar-padding: 1px;
$text-padding: 8px;
.switch-bar{
  position: relative;
  display: inline-block;
  box-sizing: border-box;
  width: $bar-width;
  height: $bar-height;
  line-height: $bar-height - 2px;
  border-radius: $bar-height / 2;
  border: 1px solid #E6E6E6;
  background-color: #BBB;
  color: #FFF;
  text-align: right;
  transition: all 0.3s ease-in-out;
  .text {
    margin: 0 $text-padding;
  }
  .switch-handle{
    position: absolute;
    left: $bar-padding;
    top: $bar-padding;
    width: $bar-height - $bar-padding * 2 - 2px;
    height: $bar-height - $bar-padding * 2 - 2px;
    border-radius: 50%;
    background-color: #FFF;
    transition: all 0.3s ease-in-out;
  }
}
.on{
  @include base-background-color();
  color: #FFF;
  text-align: left;
  .switch-handle{
    background-color: #FFF;
    transform: translateX($bar-width - $bar-height);
  }
}
.disabled {
  background-color: #E5E5E5;
  cursor: not-allowed;
  .switch-handle{
    background-color: #F2F2F2;
  }
}
.disabled-on{
  .switch-handle{
    background-color: #F9F9F9;
  }
  &:before {
    content: '';
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(255, 255, 255, .5);
    border-radius: $bar-height / 2;
  }
}

</style>
<style lang="scss" scoped>
$bar-width: 116px;
$bar-height: 60px;
$bar-padding: 4px;
$text-padding: 20px;
@media (max-width: $max-mobile-width) {
  .switch-bar{
    box-sizing: content-box;
    width: $bar-width;
    height: $bar-height;
    line-height: $bar-height;
    border-radius: $bar-height / 2;/*yes*/
    .switch-handle{
      left: $bar-padding;
      top: $bar-padding;
      width: $bar-height - $bar-padding * 2;
      height: $bar-height - $bar-padding * 2;
    }
  }
  .on{
    .switch-handle{
      transform: translateX($bar-width - $bar-height);
    }
  }
  .disabled-on:before {
    border-radius: $bar-height / 2;
  }
}
</style>

感谢评论区大佬的点拨。

希望看完的朋友可以给个赞,鼓励一下