| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- <template>
- <view
- class="cl-checkbox"
- :class="[
- {
- 'cl-checkbox--disabled': disabled,
- '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";
- 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();
- // 透传样式类型定义
- 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 (!props.disabled) {
- 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-70;
- }
- }
- </style>
|