90 lines
1.7 KiB
Vue
90 lines
1.7 KiB
Vue
<template>
|
|
<label
|
|
class="radio-wrapper"
|
|
:class="{ 'radio-wrapper--disabled': isDisabled }"
|
|
@click.stop="handleClick"
|
|
>
|
|
<radio
|
|
class="radio"
|
|
:value="String(name)"
|
|
:checked="isChecked"
|
|
:disabled="isDisabled"
|
|
:color="isChecked ? '#0083ff' : ''"
|
|
:name="String(name)"
|
|
/>
|
|
<view class="radio-label" :class="{ 'radio-label--active': isChecked }">
|
|
<slot>{{ label }}</slot>
|
|
</view>
|
|
</label>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, inject } from 'vue'
|
|
|
|
const props = defineProps({
|
|
name: {
|
|
type: [String, Number],
|
|
required: true,
|
|
},
|
|
label: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
})
|
|
|
|
interface RadioGroupContext {
|
|
modelValue: ComputedRef<string | number>
|
|
disabled: ComputedRef<boolean>
|
|
toggleOption: (value: string | number) => void
|
|
}
|
|
|
|
// 注入radio group的上下文
|
|
const radioGroup = inject<RadioGroupContext>('radioGroup', {
|
|
modelValue: computed(() => ''),
|
|
disabled: computed(() => false),
|
|
toggleOption: () => {},
|
|
})
|
|
|
|
// 是否选中
|
|
const isChecked = computed(() => {
|
|
return radioGroup.modelValue.value === props.name
|
|
})
|
|
|
|
// 是否禁用
|
|
const isDisabled = computed(() => {
|
|
return props.disabled || radioGroup.disabled.value
|
|
})
|
|
|
|
// 处理点击事件
|
|
const handleClick = () => {
|
|
if (isDisabled.value) return
|
|
radioGroup.toggleOption(props.name)
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.radio-wrapper {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
font-size: 28rpx;
|
|
padding: 8rpx 0;
|
|
|
|
&--disabled {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
.radio-label {
|
|
margin-left: 10rpx;
|
|
line-height: 1;
|
|
|
|
&--active {
|
|
color: #0083ff;
|
|
}
|
|
}
|
|
</style>
|