fs-switch.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <template>
  2. <view
  3. class="fs-switch"
  4. :class="[{ 'fs-switch-checked': modelValue, 'fs-switch-disabled': disabled }, 'fs-switch-' + size]"
  5. @click="handleClick"
  6. >
  7. <view class="fs-switch-text">{{ modelValue ? activeText : inactiveText }}</view>
  8. </view>
  9. </template>
  10. <script>
  11. /**
  12. * 开关组件
  13. * @description 开关组件
  14. * @property {String} activeColor switch的值为 on 的颜色
  15. * @property {String} inactiveColor switch的值为 off 的颜色
  16. * @property {Boolean} disabled 是否禁用
  17. * @property {String} activeText switch的值为 on 的文字
  18. * @property {String} inactiveText switch的值为 off 的文字
  19. * @property {String} size = [small | default | large] 开关大小
  20. * @event {Function} change change事件
  21. */
  22. export default {
  23. name: 'fs-switch'
  24. }
  25. </script>
  26. <script setup>
  27. import { watch, ref } from 'vue'
  28. const props = defineProps({
  29. modelValue: Boolean,
  30. disabled: Boolean,
  31. activeColor: {
  32. type: String,
  33. default: '#0063F5'
  34. },
  35. inactiveColor: {
  36. type: String,
  37. default: '#fdfdfd'
  38. },
  39. activeText: String,
  40. inactiveText: String,
  41. size: {
  42. type: String,
  43. validator(value) {
  44. return ['small', 'default', 'large'].includes(value)
  45. }
  46. }
  47. })
  48. const emits = defineEmits(['change', 'update:modelValue'])
  49. const handleClick = () => {
  50. if (!props.disabled) {
  51. emits('update:modelValue', !props.modelValue)
  52. emits('change', !props.modelValue)
  53. }
  54. }
  55. </script>
  56. <style lang="scss" scoped>
  57. .fs-switch {
  58. width: 80rpx;
  59. height: 40rpx;
  60. border-radius: 50rpx;
  61. position: relative;
  62. background-color: v-bind(inactiveColor);
  63. border: 2rpx solid rgba(0, 0, 0, 0.12);
  64. transition: background-color 0.1s;
  65. &::before {
  66. width: 36rpx;
  67. height: 36rpx;
  68. border-radius: 50%;
  69. content: '';
  70. position: absolute;
  71. top: 0;
  72. left: 0;
  73. background-color: #fff;
  74. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  75. transition: transform 0.3s;
  76. z-index: 10;
  77. }
  78. &-text {
  79. position: absolute;
  80. top: 50%;
  81. left: 50%;
  82. transform: translateY(-50%);
  83. font-size: 12px;
  84. transition: all 0.3s;
  85. text-align: center;
  86. width: 30rpx;
  87. overflow: hidden;
  88. }
  89. &-disabled {
  90. opacity: 0.5;
  91. }
  92. &-checked {
  93. background-color: v-bind(activeColor);
  94. &::before {
  95. transform: translateX(40rpx);
  96. }
  97. .fs-switch-text {
  98. color: #fff;
  99. margin-left: -30rpx;
  100. }
  101. }
  102. &-large {
  103. transform: scale(1.2);
  104. }
  105. &-small {
  106. transform: scale(0.8);
  107. }
  108. }
  109. </style>