123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- <template>
- <view
- class="fs-switch"
- :class="[{ 'fs-switch-checked': modelValue, 'fs-switch-disabled': disabled }, 'fs-switch-' + size]"
- @click="handleClick"
- >
- <view class="fs-switch-text">{{ modelValue ? activeText : inactiveText }}</view>
- </view>
- </template>
- <script>
- /**
- * 开关组件
- * @description 开关组件
- * @property {String} activeColor switch的值为 on 的颜色
- * @property {String} inactiveColor switch的值为 off 的颜色
- * @property {Boolean} disabled 是否禁用
- * @property {String} activeText switch的值为 on 的文字
- * @property {String} inactiveText switch的值为 off 的文字
- * @property {String} size = [small | default | large] 开关大小
- * @event {Function} change change事件
- */
- export default {
- name: 'fs-switch'
- }
- </script>
- <script setup>
- import { watch, ref } from 'vue'
- const props = defineProps({
- modelValue: Boolean,
- disabled: Boolean,
- activeColor: {
- type: String,
- default: '#0063F5'
- },
- inactiveColor: {
- type: String,
- default: '#fdfdfd'
- },
- activeText: String,
- inactiveText: String,
- size: {
- type: String,
- validator(value) {
- return ['small', 'default', 'large'].includes(value)
- }
- }
- })
- const emits = defineEmits(['change', 'update:modelValue'])
- const handleClick = () => {
- if (!props.disabled) {
- emits('update:modelValue', !props.modelValue)
- emits('change', !props.modelValue)
- }
- }
- </script>
- <style lang="scss" scoped>
- .fs-switch {
- width: 80rpx;
- height: 40rpx;
- border-radius: 50rpx;
- position: relative;
- background-color: v-bind(inactiveColor);
- border: 2rpx solid rgba(0, 0, 0, 0.12);
- transition: background-color 0.1s;
- &::before {
- width: 36rpx;
- height: 36rpx;
- border-radius: 50%;
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- background-color: #fff;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
- transition: transform 0.3s;
- z-index: 10;
- }
- &-text {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translateY(-50%);
- font-size: 12px;
- transition: all 0.3s;
- text-align: center;
- width: 30rpx;
- overflow: hidden;
- }
- &-disabled {
- opacity: 0.5;
- }
- &-checked {
- background-color: v-bind(activeColor);
- &::before {
- transform: translateX(40rpx);
- }
- .fs-switch-text {
- color: #fff;
- margin-left: -30rpx;
- }
- }
- &-large {
- transform: scale(1.2);
- }
- &-small {
- transform: scale(0.8);
- }
- }
- </style>
|