u-switch.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <view class="container" @click="toggleSwitch">
  3. <label :class="isOn ? 'switch-checked' : 'switch-nochecked'">
  4. <view class="open">{{ activeText }}</view>
  5. <view class="close">{{ inactiveText }}</view>
  6. </label>
  7. </view>
  8. </template>
  9. <script setup>
  10. import {
  11. ref,
  12. watch,
  13. } from 'vue';
  14. const props = defineProps({
  15. value: {
  16. type: Boolean,
  17. default: false
  18. },
  19. activeText: {
  20. type: String,
  21. default: '已上线'
  22. },
  23. inactiveText: {
  24. type: String,
  25. default: '已下线'
  26. },
  27. activeValue: {
  28. type: [Number, String, Boolean],
  29. default: true
  30. },
  31. inactiveValue: {
  32. type: [Number, String, Boolean],
  33. default: false
  34. },
  35. });
  36. const emit = defineEmits(['update:value', 'change']);
  37. const isOn = ref(props.value);
  38. watch(() => props.value, (newVal) => {
  39. isOn.value = newVal;
  40. });
  41. const toggleSwitch = () => {
  42. isOn.value = !isOn.value;
  43. emit('update:value', isOn.value ? props.activeValue : props.inactiveValue);
  44. emit('change', isOn.value ? props.activeValue : props.inactiveValue);
  45. };
  46. </script>
  47. <style lang="scss" scoped>
  48. .container {
  49. width: 156rpx;
  50. padding: 10rpx;
  51. label {
  52. position: relative;
  53. display: block;
  54. border-radius: 40rpx;
  55. width: 100%;
  56. &:before {
  57. content: " ";
  58. display: block;
  59. border-radius: 50rpx;
  60. height: 50rpx;
  61. background-color: #d5d5d5;
  62. transform: scale(1, 1);
  63. transition: all 0.3s ease;
  64. }
  65. &:after {
  66. content: "";
  67. position: absolute;
  68. top: 3rpx;
  69. left: 0;
  70. width: 44rpx;
  71. height: 44rpx;
  72. border-radius: 50%;
  73. background: #fff;
  74. border: 2rpx solid #e0e0e0;
  75. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
  76. transition: all 0.3s cubic-bezier(.4, 0, .2, 1);
  77. z-index: 2;
  78. }
  79. }
  80. %font-style {
  81. top: 0;
  82. color: #ffffff;
  83. font-size: 28rpx;
  84. height: 100%;
  85. line-height: 50rpx;
  86. position: absolute;
  87. transition: all 1s ease;
  88. }
  89. .switch-checked {
  90. &:after {
  91. left: unset;
  92. right: 5rpx;
  93. top: 1.5rpx;
  94. border: 2rpx solid #FFDA59;
  95. }
  96. &:before {
  97. background-color: #FFDA59;
  98. }
  99. .close {
  100. display: none;
  101. }
  102. }
  103. .switch-nochecked {
  104. &:before {
  105. background-color: #d5d5d5;
  106. }
  107. &:after {
  108. left: 5rpx;
  109. top: 1.5rpx;
  110. border: 2rpx solid #d5d5d5;
  111. }
  112. .open {
  113. display: none;
  114. }
  115. }
  116. .open {
  117. left: 20rpx;
  118. @extend %font-style;
  119. font-size: 26rpx;
  120. color: #56441B;
  121. display: flex;
  122. align-items: center;
  123. height: 56rpx;
  124. position: absolute;
  125. top: 0;
  126. }
  127. .close {
  128. right: 20rpx;
  129. @extend %font-style;
  130. font-size: 26rpx;
  131. color: #56441B;
  132. display: flex;
  133. align-items: center;
  134. height: 56rpx;
  135. position: absolute;
  136. top: 0;
  137. }
  138. }
  139. </style>