137 lines
2.8 KiB
Vue
137 lines
2.8 KiB
Vue
<template>
|
||
<view
|
||
:style="`${defaultStyle}`"
|
||
:class="`${isChecked?'checkbox-active':''} ${isDisabled?'checkbox-disabled':''} ${rootClass}`"
|
||
@click="handleClick"
|
||
>
|
||
<view class="checkbox__icon" :class="{ 'checkbox__icon--checked': isChecked }" v-if="showIcon">
|
||
<text v-if="isChecked" class="i-carbon-checkmark checkbox__icon-check"></text>
|
||
</view>
|
||
<view class="checkbox__label">
|
||
<slot>{{ label }}</slot>
|
||
</view>
|
||
</view>
|
||
</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,
|
||
},
|
||
showIcon:{
|
||
default:false
|
||
},
|
||
defaultStyle:{
|
||
type:String,
|
||
default: 'display: inline-flex;align-items: center;cursor: pointer;font-size: 28rpx;'
|
||
},
|
||
checkboxActive:{
|
||
default:'background-color: #0083ff;border-color: #0083ff;'
|
||
},
|
||
rootClass:{
|
||
type:String,
|
||
default: ""
|
||
}
|
||
})
|
||
|
||
const emit = defineEmits(['change'])
|
||
|
||
interface CheckboxGroupContext {
|
||
modelValue: ComputedRef<any[]>
|
||
disabled: ComputedRef<boolean>
|
||
max: ComputedRef<number>
|
||
selectedCount: ComputedRef<number>
|
||
toggleOption: (option: { value: string | number }) => void
|
||
}
|
||
|
||
// 注入checkbox group的上下文
|
||
const checkboxGroup = inject<CheckboxGroupContext>('checkboxGroup', {
|
||
modelValue: computed(() => []),
|
||
disabled: computed(() => false),
|
||
max: computed(() => 0),
|
||
selectedCount: computed(() => 0),
|
||
toggleOption: () => {},
|
||
})
|
||
|
||
// 是否选中
|
||
const isChecked = computed(() => {
|
||
const modelValue = checkboxGroup.modelValue.value
|
||
return modelValue.includes(props.name)
|
||
})
|
||
|
||
// 是否禁用
|
||
const isDisabled = computed(() => {
|
||
const max = checkboxGroup.max.value
|
||
const selectedCount = checkboxGroup.selectedCount.value
|
||
// 如果有原始禁用属性,或者group禁用,或者达到最大选择数且未选中,则禁用
|
||
return (
|
||
props.disabled ||
|
||
checkboxGroup.disabled.value ||
|
||
(max > 1 && !isChecked.value && selectedCount >= max)
|
||
)
|
||
})
|
||
|
||
// 处理点击事件
|
||
const handleClick = () => {
|
||
if (isDisabled.value) return
|
||
|
||
checkboxGroup.toggleOption({
|
||
value: props.name,
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
|
||
.checkbox--disabled {
|
||
cursor: not-allowed;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.checkbox__icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border: 2rpx solid #dcdfe6;
|
||
border-radius: 4rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 8rpx;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.checkbox__icon--checked {
|
||
border-color: #0083ff;
|
||
}
|
||
|
||
.checkbox__icon-check {
|
||
color: #fff;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.checkbox__label {
|
||
line-height: 1;
|
||
}
|
||
|
||
.checkbox-active {
|
||
border:var(--checkbox-active-border);
|
||
color: var(--checkbox-active-color)
|
||
}
|
||
|
||
.checkbox-disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed !important;
|
||
}
|
||
</style>
|