163 lines
3.3 KiB
Vue
163 lines
3.3 KiB
Vue
<template>
|
|
<view>
|
|
<view class="q-switch-box" :style="{
|
|
backgroundColor: modelValue ? activeBgColor : inActiveBgColor,
|
|
width: width,
|
|
height: height,
|
|
borderRadius: `calc(${height} / 2)`,
|
|
}" @click.stop="changeSwitch"
|
|
:class="{disabled:disabled&&openDisabledClass}"
|
|
>
|
|
<view v-show="!modelValue" class="before" :style="{
|
|
left: `calc(${margin} * 2)`,
|
|
}">
|
|
<slot name="left">{{ inShowText }}</slot>
|
|
</view>
|
|
<!-- 圆圈 -->
|
|
<view class="circle-inner" :style="{
|
|
margin: margin,
|
|
width: circleRadius,
|
|
height: circleRadius,
|
|
backgroundColor: '#ffffff',
|
|
...switchAnimation,
|
|
}"></view>
|
|
<view v-show="modelValue" class="after" :style="{
|
|
right: `calc(${margin} * 2)`,
|
|
}">
|
|
<slot name="right">{{ showText }}</slot>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<!-- 自定义Switch:自定义左右内容 -->
|
|
<script setup>
|
|
import {
|
|
computed,
|
|
ref
|
|
} from 'vue'
|
|
const props = defineProps({
|
|
disabled:{
|
|
type:Boolean,
|
|
default:false
|
|
},
|
|
openDisabledClass:{
|
|
type:Boolean,
|
|
default:true
|
|
},
|
|
height: {
|
|
type: String,
|
|
default: '40rpx',
|
|
},
|
|
width: {
|
|
type: String,
|
|
default: '78rpx',
|
|
},
|
|
margin: {
|
|
type: String,
|
|
default: '4rpx',
|
|
},
|
|
fontSize: {
|
|
type: String,
|
|
default: '32rpx',
|
|
},
|
|
// 激活背景色
|
|
activeBgColor: {
|
|
type: String,
|
|
default: '#318AFE',
|
|
},
|
|
// 未激活背景色
|
|
inActiveBgColor: {
|
|
type: String,
|
|
default: '#ECECEC',
|
|
},
|
|
// 激活文本
|
|
showText: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
// 未激活文本
|
|
inShowText: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
// v-modal
|
|
modelValue: {
|
|
type: [Boolean,Number],
|
|
default: false,
|
|
},
|
|
})
|
|
const emits = defineEmits(['update:modelValue', 'change','click'])
|
|
// 修改switch值
|
|
function changeSwitch() {
|
|
if(props.disabled){
|
|
emits('click')
|
|
return
|
|
}
|
|
let currentVal=props.modelValue
|
|
let type=typeof currentVal
|
|
if(type==='number'){
|
|
currentVal=currentVal===0?1:0
|
|
}
|
|
if(type==='boolean'){
|
|
currentVal=!currentVal
|
|
}
|
|
emits('update:modelValue', currentVal)
|
|
emits('change', currentVal)
|
|
}
|
|
// 圆圈半径
|
|
let circleRadius = computed(() => {
|
|
return `calc(((${props.height} / 2) - ${props.margin})* 2)`
|
|
})
|
|
// 动画效果
|
|
let switchAnimation = computed(() => {
|
|
let obj = {
|
|
transition: `transform 0.3s`,
|
|
transform: 'translateX(0)',
|
|
}
|
|
//激活
|
|
if (props.modelValue) {
|
|
let innerRadius = `((${props.height} / 2) - ${props.margin})` //圆圈半径
|
|
let moveValue =
|
|
`calc(${props.width} - ${props.margin} * 2 - (${innerRadius} * 2))` //偏移距离 总宽度 - 圆圈左右边距 - 圆圈宽度
|
|
// console.log('move-value', moveValue)
|
|
obj.transform = `translateX(${moveValue})`
|
|
} else {
|
|
// 未激活
|
|
obj.transform = 'translateX(0)'
|
|
}
|
|
return obj
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.q-switch-box {
|
|
display: flex;
|
|
background-color: #eaeaea;
|
|
position: relative;
|
|
height: 100%;
|
|
&.disabled{
|
|
opacity: .5;
|
|
}
|
|
.circle-inner {
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.before {
|
|
position: absolute;
|
|
color: #bbbbbb;
|
|
font-size: 28rpx;
|
|
display: flex;
|
|
height: 100%;
|
|
align-items: center;
|
|
}
|
|
|
|
.after {
|
|
position: absolute;
|
|
font-size: 28rpx;
|
|
color: #ffffff;
|
|
display: flex;
|
|
height: 100%;
|
|
align-items: center;
|
|
}
|
|
}
|
|
</style> |