Switch.vue 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <template>
  2. <span
  3. class="switch"
  4. :class="{
  5. 'active': value,
  6. 'disabled': disabled,
  7. }"
  8. @click="handleChange()"
  9. >
  10. <span class="switch-core"></span>
  11. </span>
  12. </template>
  13. <script lang="ts" setup>
  14. const props = withDefaults(defineProps<{
  15. value: boolean
  16. disabled?: boolean
  17. }>(), {
  18. disabled: false,
  19. })
  20. const emit = defineEmits<{
  21. (event: 'update:value', payload: boolean): void
  22. }>()
  23. const handleChange = () => {
  24. if (props.disabled) return
  25. emit('update:value', !props.value)
  26. }
  27. </script>
  28. <style lang="scss" scoped>
  29. .switch {
  30. height: 20px;
  31. display: inline-block;
  32. cursor: pointer;
  33. &:not(.disabled).active {
  34. .switch-core {
  35. border-color: $themeColor;
  36. background-color: $themeColor;
  37. &::after {
  38. left: 100%;
  39. margin-left: -17px;
  40. }
  41. }
  42. }
  43. &.disabled {
  44. cursor: default;
  45. .switch-core::after {
  46. background-color: #f5f5f5;
  47. }
  48. }
  49. }
  50. .switch-core {
  51. margin: 0;
  52. display: inline-block;
  53. position: relative;
  54. width: 40px;
  55. height: 20px;
  56. border: 1px solid #d9d9d9;
  57. outline: none;
  58. border-radius: 10px;
  59. box-sizing: border-box;
  60. background: #d9d9d9;
  61. transition: border-color .3s, background-color .3s;
  62. vertical-align: middle;
  63. &::after {
  64. content: '';
  65. position: absolute;
  66. top: 1px;
  67. left: 1px;
  68. border-radius: 100%;
  69. transition: all .3s;
  70. width: 16px;
  71. height: 16px;
  72. background-color: #fff;
  73. }
  74. }
  75. </style>