Files
WAI_Project_UNIX/uni_modules/cool-ui/components/cl-checkbox/cl-checkbox.uvue
2025-08-06 16:30:49 +08:00

178 lines
3.1 KiB
Plaintext

<template>
<view
class="cl-checkbox"
:class="[
{
'cl-checkbox--disabled': isDisabled,
'cl-checkbox--checked': isChecked
},
pt.className
]"
@tap="onTap"
>
<cl-icon
v-if="showIcon"
:name="iconName"
:size="pt.icon?.size ?? 40"
:pt="{
className: parseClass([
'cl-checkbox__icon mr-1',
{
'!text-primary-500': isChecked
},
pt.icon?.className
])
}"
></cl-icon>
<cl-text
:pt="{
className: parseClass([
'cl-checkbox__label',
{
'!text-primary-500': isChecked
},
pt.label?.className
])
}"
v-if="showLabel"
>
<slot>{{ label }}</slot>
</cl-text>
</view>
</template>
<script lang="ts" setup>
import { computed, useSlots, type PropType } from "vue";
import type { PassThroughProps } from "../../types";
import { get, parseClass, parsePt, pull } from "@/cool";
import type { ClIconProps } from "../cl-icon/props";
import { useForm } from "../../hooks";
defineOptions({
name: "cl-checkbox"
});
// 定义组件属性
const props = defineProps({
// 透传样式配置
pt: {
type: Object,
default: () => ({})
},
// 绑定值 - 当前选中的值
modelValue: {
type: [Array, Boolean] as PropType<any[] | boolean>,
default: () => []
},
// 标签文本
label: {
type: String,
default: ""
},
// 选项值 - 该单选框对应的值
value: {
type: null
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 选中时的图标
activeIcon: {
type: String,
default: "checkbox-line"
},
// 未选中时的图标
inactiveIcon: {
type: String,
default: "checkbox-blank-line"
},
// 是否显示图标
showIcon: {
type: Boolean,
default: true
}
});
// 定义组件事件
const emit = defineEmits(["update:modelValue", "change"]);
const slots = useSlots();
const { disabled } = useForm();
// 是否禁用
const isDisabled = computed(() => props.disabled || disabled.value);
// 透传样式类型定义
type PassThrough = {
className?: string;
icon?: ClIconProps;
label?: PassThroughProps;
};
// 解析透传样式配置
const pt = computed(() => parsePt<PassThrough>(props.pt));
// 是否为选中状态
const isChecked = computed(() => {
if (Array.isArray(props.modelValue)) {
return props.modelValue.includes(props.value!);
}
if (typeof props.modelValue == "boolean") {
return props.modelValue;
}
return false;
});
// 是否显示标签
const showLabel = computed(() => props.label != "" || get(slots, "default") != null);
// 图标名称
const iconName = computed(() => {
// 选中状态
if (isChecked.value) {
return props.activeIcon;
}
// 默认状态
return props.inactiveIcon;
});
/**
* 点击事件处理函数
* 在非禁用状态下切换选中状态
*/
function onTap() {
if (!isDisabled.value) {
let val = props.modelValue;
if (Array.isArray(val)) {
if (isChecked.value) {
val = pull(val, props.value!);
} else {
val.push(props.value!);
}
} else {
val = !val;
}
emit("update:modelValue", val);
emit("change", val);
}
}
</script>
<style lang="scss" scoped>
.cl-checkbox {
@apply flex flex-row items-center;
&--disabled {
@apply opacity-50;
}
}
</style>