Files
sh-app/components/nbd-check-btn.vue
T
2026-07-02 19:36:49 +08:00

119 lines
2.6 KiB
Vue

<template>
<view class="check-seg">
<view
class="check-seg__item"
:class="{ 'check-seg__item--active': isPass, 'is-active-anim': isPass && animKey === 'pass' }"
@click="select(passKey)"
>
<text class="check-seg__icon">{{ '\u2713' }}</text>
<text class="check-seg__text">{{ passText }}</text>
</view>
<view
class="check-seg__item"
:class="{ 'check-seg__item--active': isFail, 'is-active-anim': isFail && animKey === 'fail' }"
@click="select(failKey)"
>
<text class="check-seg__icon">{{ '\u2717' }}</text>
<text class="check-seg__text">{{ failText }}</text>
</view>
</view>
</template>
<script setup>
import { computed, ref, watch, nextTick } from 'vue'
const props = defineProps({
modelValue: { type: [Boolean, Object], default: null },
passKey: { type: String, default: 'pass' },
failKey: { type: String, default: 'fail' },
passText: { type: String, default: '通过' },
failText: { type: String, default: '不通过' }
})
const emit = defineEmits(['update:modelValue'])
const isPass = computed(() => props.modelValue === props.passKey)
const isFail = computed(() => props.modelValue === props.failKey)
const animKey = ref('')
watch(() => props.modelValue, async () => {
animKey.value = ''
await nextTick()
animKey.value = isPass.value ? 'pass' : 'fail'
})
const select = (key) => {
emit('update:modelValue', key)
}
</script>
<style lang="scss" scoped>
.check-seg {
display: inline-flex;
border-radius: 12rpx;
overflow: hidden;
border: 1rpx solid #e5e7eb;
&__item {
display: flex;
align-items: center;
gap: 6rpx;
padding: 12rpx 24rpx;
transition: all 0.25s ease;
background: #f9fafb;
&:first-child {
border-right: 1rpx solid #e5e7eb;
}
&:active {
transform: scale(0.96);
}
&--active {
background: #ebf9f0;
.check-seg__icon { color: #22c55e; }
.check-seg__text { color: #16a34a; font-weight: 600; }
&:first-child {
border-right-color: #b7ebc6;
}
}
&--active:not(:first-child) {
background: #fef2f2;
.check-seg__icon { color: #ef4444; }
.check-seg__text { color: #dc2626; font-weight: 600; }
}
}
&__icon {
font-size: 24rpx;
color: #9ca3af;
font-weight: 700;
transition: color 0.25s ease;
}
&__text {
font-size: 24rpx;
color: #6b7280;
font-weight: 500;
transition: color 0.25s ease;
}
}
// ===== 激活动画(双选分段) =====
@keyframes popIn {
0% { transform: scale(0.5); opacity: 0; }
60% { transform: scale(1.15); }
100% { transform: scale(1); opacity: 1; }
}
.check-seg__item.is-active-anim .check-seg__icon {
animation: popIn 0.3s ease-out;
}
</style>