yunshangxie/tuniao-ui/components/tn-switch/tn-switch.vue

242 lines
5.4 KiB
Vue
Raw Normal View History

2023-12-25 17:56:30 +08:00
<template>
<view
class="tn-switch-class tn-switch"
:class="[
value ? 'tn-switch--on' : '',
disabled ? 'tn-switch--disabled' : '',
`tn-switch--${shape}`
]"
:style="[switchStyle]"
@tap="click"
>
<view
class="tn-switch__node"
:class="[`tn-switch__node--${shape}`]"
:style="[switchNodeStyle]"
>
<tn-loading class="tn-switch__node__loading" :show="loading" mode="flower" :size="size * 0.6" :color="loadingColor"></tn-loading>
</view>
<!-- 左图标 -->
<view
v-if="leftIcon !== ''"
class="tn-switch__icon tn-switch__icon--left"
:class="[
`tn-icon-${leftIcon}`,
value ? 'tn-switch__icon--show' : ''
]"
:style="[iconStyle]"></view>
<!-- 右图标 -->
<view
v-if="rightIcon !== ''"
class="tn-switch__icon tn-switch__icon--right"
:class="[
`tn-icon-${rightIcon}`,
!value ? 'tn-switch__icon--show' : ''
]"
:style="[iconStyle]"></view>
</view>
</template>
<script>
export default {
name: 'tn-switch',
props: {
value: {
type: Boolean,
default: false
},
// 按钮的样式
// circle 圆角 square 方形
shape: {
type: String,
default: 'circle'
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 尺寸
size: {
type: Number,
default: 50
},
// 打开时的背景颜色
activeColor: {
type: String,
default: ''
},
// 关闭时的背景颜色
inactiveColor: {
type: String,
default: ''
},
// 激活时的值
activeValue: {
type: [Number, String, Boolean],
default: true
},
// 关闭时的值
inactiveValue: {
type: [Number, String, Boolean],
default: false
},
// 左图标
leftIcon: {
type: String,
default: ''
},
// 右图标
rightIcon: {
type: String,
default: ''
},
// 是否为加载状态
loading: {
type: Boolean,
default: false
},
// 点击手机是否震动
vibrateShort: {
type: Boolean,
default: false
}
},
computed: {
switchStyle() {
let style = {}
style.fontSize = this.$tn.string.getLengthUnitValue(this.size)
style.backgroundColor = this.value ?
this.activeColor ? this.activeColor : '#01BEFF' :
this.inactiveColor ? this.inactiveColor : '#AAAAAA'
return style
},
switchNodeStyle() {
let style = {}
style.width = this.$tn.string.getLengthUnitValue(this.size)
style.height = style.width
return style
},
iconStyle() {
let style = {}
style.fontSize = this.$tn.string.getLengthUnitValue(this.size - 20)
style.lineHeight = this.$tn.string.getLengthUnitValue(this.size)
return style
},
loadingColor() {
return this.value ? this.activeColor : ''
}
},
data() {
return {
}
},
methods: {
click() {
if (!this.disabled && !this.loading) {
if (this.vibrateShort) uni.vibrateShort()
this.$emit('input', !this.value)
// 放到下一个生命周期因为双向绑定的value修改父组件状态需要时间且是异步的
this.$nextTick(() => {
this.$emit('change', this.value ? this.activeValue : this.inactiveValue);
})
}
}
}
}
</script>
<style lang="scss" scoped>
.tn-switch {
/* #ifndef APP-NVUE */
display: inline-block;
/* #endif */
position: relative;
box-sizing: initial;
width: 2em;
height: 1em;
font-size: 50rpx;
background-color: #AAAAAA;
transition: background-color 0.3s;
&__node {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
z-index: 1;
background-color: #FFFFFF;
transform: scale(0.9);
box-shadow: 0 6rpx 2rpx 0 rgba(0, 0, 0, 0.05), 0 4rpx 4rpx 0 rgba(0, 0, 0, 0.1), 0 6rpx 6rpx 0 rgba(0, 0, 0, 0.05);
transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);
-webkit-transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);
&__loading {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
&--circle {
border-radius: 100%;
}
&--square {
border-radius: 15%;
}
}
&__icon {
color: #FFFFFF;
font-size: 30rpx;
line-height: 50rpx;
height: 100%;
vertical-align: middle;
position: absolute;
transform: scale(0);
transform-origin: 50% 50%;
transition: transform 0.3s ease-in-out;
&--left {
top: 0;
left: 10rpx;
}
&--right {
top: 0;
right: 10rpx;
}
&--show {
transform: scale(1);
}
}
&--circle {
border-radius: 1em;
}
&--square {
border-radius: 0.1em;
}
&--on {
background-color: $tn-main-color;
.tn-switch__node {
transform: translateX(100%) scale(0.9);
}
}
&--disabled {
opacity: 0.4;
}
}
</style>