2026-04-22 10:30:55 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="radio-button-group">
|
|
|
|
|
<button
|
|
|
|
|
v-for="item in options"
|
2026-05-11 11:28:59 +08:00
|
|
|
:key="String(item.value)"
|
2026-04-22 10:30:55 +08:00
|
|
|
type="button"
|
|
|
|
|
:class="[
|
|
|
|
|
'radio-button',
|
|
|
|
|
{
|
|
|
|
|
'is-active': multiple ? selectedValues.includes(item.value) : modelValue === item.value
|
|
|
|
|
}
|
|
|
|
|
]"
|
|
|
|
|
@click="selectOption(item.value)"
|
|
|
|
|
>
|
|
|
|
|
{{ item.name }}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed } from 'vue'
|
|
|
|
|
|
|
|
|
|
interface Option {
|
|
|
|
|
name: string | number
|
|
|
|
|
value: string | number | boolean
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
modelValue: string | number | boolean | Array<string | number | boolean> | null
|
|
|
|
|
options: Option[] // 按钮选项数组
|
|
|
|
|
multiple?: boolean // 是否支持多选,默认为 false
|
2026-04-22 16:11:16 +08:00
|
|
|
max?: number // 多选时最多可选数量,不传则不限制
|
2026-04-22 10:30:55 +08:00
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
(e: 'update:modelValue', value: any): void
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const multiple = props.multiple === true
|
|
|
|
|
|
|
|
|
|
const selectedValues = computed(() => {
|
|
|
|
|
if (!multiple) {
|
|
|
|
|
return typeof props.modelValue === 'undefined' || props.modelValue === null
|
|
|
|
|
? []
|
|
|
|
|
: [props.modelValue]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Array.isArray(props.modelValue) ? props.modelValue : []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const selectOption = (value: any) => {
|
|
|
|
|
if (multiple) {
|
|
|
|
|
const current = Array.isArray(props.modelValue) ? [...props.modelValue] : []
|
|
|
|
|
const index = current.indexOf(value)
|
|
|
|
|
if (index >= 0) {
|
|
|
|
|
current.splice(index, 1)
|
|
|
|
|
} else {
|
2026-04-22 16:11:16 +08:00
|
|
|
if (typeof props.max === 'number' && props.max > 0 && current.length >= props.max) {
|
|
|
|
|
current.shift()
|
|
|
|
|
}
|
2026-04-22 10:30:55 +08:00
|
|
|
current.push(value)
|
|
|
|
|
}
|
|
|
|
|
emit('update:modelValue', current)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (props.modelValue !== value) {
|
|
|
|
|
emit('update:modelValue', value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.radio-button-group {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 0.8rem;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.radio-button {
|
|
|
|
|
border: 1px solid #979797;
|
|
|
|
|
height: 4rem;
|
|
|
|
|
min-width: 8rem;
|
|
|
|
|
padding: 0 2rem;
|
|
|
|
|
color: #979797;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
outline: none;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
font-size: 1.4rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.radio-button:hover {
|
|
|
|
|
border-color: #000;
|
|
|
|
|
color: #fff;
|
|
|
|
|
background-color: #000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.radio-button.is-active {
|
|
|
|
|
color: #fff;
|
|
|
|
|
background-color: #000;
|
|
|
|
|
border-color: #000;
|
|
|
|
|
}
|
|
|
|
|
</style>
|