| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- <template>
- <view class="container" @click="toggleSwitch">
- <view :class="['switch', isOn ? 'switch-checked' : 'switch-nochecked']">
- <!-- background handled by switch itself -->
- <view
- class="switch-handle"
- :style="isOn ? 'left: 0;' : 'right: 0;'"
- ></view>
- <text v-if="isOn">{{ activeText }}</text>
- <text v-else>{{ inactiveText }}</text>
- </view>
- </view>
- </template>
- <script setup>
- import {
- ref,
- watch,
- } from 'vue';
- const props = defineProps({
- value: {
- type: Boolean,
- default: false
- },
- activeText: {
- type: String,
- default: '已上线'
- },
- inactiveText: {
- type: String,
- default: '已下线'
- },
- activeValue: {
- type: [Number,
- String,
- Boolean],
- default: true
- },
- inactiveValue: {
- type: [Number,
- String,
- Boolean],
- default: false
- },
- });
- const emit = defineEmits(['update:value', 'change']);
- const isOn = ref(props.value);
-
- // keep `isOn` in sync when prop changes using watchEffect to avoid
- // generics/return-type confusion in UTS.
- watchEffect(() => {
- const v = props.value;
- if (v != null) {
- isOn.value = v as boolean;
- }
- });
- const toggleSwitch = () => {
- isOn.value = !isOn.value;
- emit('update:value', isOn.value ? props.activeValue : props.inactiveValue);
- emit('change', isOn.value ? props.activeValue : props.inactiveValue);
- };
- </script>
- <style lang="scss" scoped>
- .container {
- width: 156rpx;
- }
- .switch {
- position: relative;
- width: 156rpx; /* match container */
- height: 50rpx;
- border-radius: 40rpx;
- background-color: #d5d5d5;
- transition: background-color 0.3s ease;
- text-align: center;
- align-items: center;
- justify-content: center;
- }
- .switch-handle {
- position: absolute;
- top: 3rpx;
- // left: 3rpx;
- width: 44rpx;
- height: 44rpx;
- border-radius: 22rpx; /* half of 44rpx handle to make it circular */
- background: #fff;
- border: 2rpx solid #e0e0e0;
- box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
- }
- .switch-checked {
- background-color: #ffda59;
- }
- .switch-nochecked {
- background-color: #d5d5d5;
- }
- .switch-checked .switch-handle {
- left: 109rpx; /* moved to other side */
- }
- </style>
|