看板
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import type { ExtractPropTypes, PropType } from 'vue';
|
||||
import type { Shape } from '../../types/global';
|
||||
import { baseProps } from '../common/props';
|
||||
import { getColor } from '../../';
|
||||
|
||||
/**
|
||||
* checkbox-group 复选框组类型定义
|
||||
* @description 供 u-checkbox-group 组件 props 使用
|
||||
*/
|
||||
|
||||
export const CheckboxGroupProps = {
|
||||
...baseProps,
|
||||
/** 绑定值,选中的复选框name组成的数组 */
|
||||
modelValue: { type: Array as PropType<(string | number)[]>, default: undefined },
|
||||
/** 最多能选中多少个checkbox */
|
||||
max: { type: Number, default: 999 },
|
||||
/** 是否禁用所有复选框 */
|
||||
disabled: { type: Boolean, default: false },
|
||||
/** 在表单内提交时的标识符 */
|
||||
name: { type: [Boolean, String], default: '' },
|
||||
/** 是否禁止点击提示语选中复选框 */
|
||||
labelDisabled: { type: Boolean, default: false },
|
||||
/** 形状,square为方形,circle为原型 */
|
||||
shape: { type: String as PropType<Shape>, default: 'square' },
|
||||
/** 选中状态下的颜色 */
|
||||
activeColor: { type: String, default: () => getColor('primary') },
|
||||
/** 组件的整体大小 */
|
||||
size: { type: [String, Number], default: 34 },
|
||||
/** 每个checkbox占u-checkbox-group的宽度 */
|
||||
width: { type: String, default: 'auto' },
|
||||
/** 是否每个checkbox都换行 */
|
||||
wrap: { type: Boolean, default: false },
|
||||
/** 图标的大小,单位rpx */
|
||||
iconSize: { type: [String, Number], default: 20 }
|
||||
};
|
||||
|
||||
export type CheckboxGroupProps = ExtractPropTypes<typeof CheckboxGroupProps>;
|
||||
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="u-checkbox-group u-clearfix" :class="customClass" :style="$u.toStyle(customStyle)">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'u-checkbox-group',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
// #ifndef MP-TOUTIAO
|
||||
virtualHost: true,
|
||||
// #endif
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCurrentInstance, computed, watch, nextTick, onMounted } from 'vue';
|
||||
import { $u, useParent, useChildren, useDebounce } from '../..';
|
||||
import { CheckboxGroupProps } from './types';
|
||||
|
||||
/**
|
||||
* checkboxGroup 开关选择器父组件Group
|
||||
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
||||
* @tutorial https://uviewpro.cn/zh/components/checkbox.html
|
||||
* @property {Array} modelValue 绑定值,选中的复选框name组成的数组(支持v-model双向绑定)
|
||||
* @property {String Number} max 最多能选中多少个checkbox(默认999)
|
||||
* @property {String Number} size 组件整体的大小,单位rpx(默认40)
|
||||
* @property {Boolean} disabled 是否禁用所有checkbox(默认false)
|
||||
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
|
||||
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox(默认false)
|
||||
* @property {String} width 宽度,需带单位
|
||||
* @property {String} shape 外观形状,shape-方形,circle-圆形(默认circle)
|
||||
* @property {Boolean} wrap 是否每个checkbox都换行(默认false)
|
||||
* @property {String} active-color 选中时的颜色,应用到所有子Checkbox组件(默认主题色primary)
|
||||
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为选中的name数组
|
||||
* @example <u-checkbox-group v-model="selectedValues">
|
||||
* <u-checkbox name="apple">苹果</u-checkbox>
|
||||
* <u-checkbox name="banana">香蕉</u-checkbox>
|
||||
* </u-checkbox-group>
|
||||
*/
|
||||
const props = defineProps(CheckboxGroupProps);
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
// 使用父组件Hook
|
||||
const { children, broadcast } = useParent('u-checkbox-group');
|
||||
const { emitToParent } = useChildren('u-checkbox-group', 'u-form-item');
|
||||
const { debounce } = useDebounce(1);
|
||||
|
||||
/**
|
||||
* 根据modelValue设置子组件状态
|
||||
*/
|
||||
function syncChildrenSelection() {
|
||||
if (!children || children.length === 0 || !props.modelValue) return;
|
||||
const modelValueSet = new Set(props.modelValue);
|
||||
children.forEach((child: any) => {
|
||||
const childValue = child.getExposed?.()?.value;
|
||||
const shouldBeChecked = modelValueSet.has(childValue);
|
||||
const isCurrentlyChecked = child.getExposed?.()?.isChecked.value;
|
||||
|
||||
if (shouldBeChecked !== isCurrentlyChecked) {
|
||||
child.getExposed?.()?.setChecked({ checked: shouldBeChecked });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听modelValue变化,同步子组件状态
|
||||
*/
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
syncChildrenSelection();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 派发 change 事件和表单校验
|
||||
*/
|
||||
function emitEvent() {
|
||||
debounce(() => {
|
||||
// 收集所有选中的 name
|
||||
let values: any[] = [];
|
||||
children.forEach((child: any) => {
|
||||
if (child.getExposed?.()?.isChecked.value) {
|
||||
values.push(child.getExposed?.()?.value);
|
||||
}
|
||||
});
|
||||
emit('change', values);
|
||||
emit('update:modelValue', values);
|
||||
setTimeout(() => {
|
||||
emitToParent('onFormChange', values);
|
||||
}, 60);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选/全不选方法
|
||||
*/
|
||||
function setAllChecked(checked: boolean) {
|
||||
if (props.disabled) {
|
||||
console.warn('u-checkbox-group已禁用,无法操作');
|
||||
return;
|
||||
}
|
||||
broadcast('setChecked', { checked });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选中的值
|
||||
*/
|
||||
function getSelectedValues() {
|
||||
return children
|
||||
.filter(child => child.getExposed?.()?.isChecked.value)
|
||||
.map(child => child.getExposed?.()?.name)
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证选择是否超过最大数量
|
||||
*/
|
||||
function validateSelection() {
|
||||
const selectedCount = children.filter(child => child.getExposed?.()?.isChecked.value).length;
|
||||
if (props.max && selectedCount >= props.max) {
|
||||
$u.toast(`超过最大选择数量: ${props.max}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
syncChildrenSelection();
|
||||
});
|
||||
});
|
||||
|
||||
// 使用defineExpose暴露给外部
|
||||
defineExpose({
|
||||
// props
|
||||
props,
|
||||
|
||||
// 方法
|
||||
emitEvent,
|
||||
setAllChecked,
|
||||
getSelectedValues,
|
||||
validateSelection,
|
||||
syncChildrenSelection,
|
||||
|
||||
// 计算属性
|
||||
selectedCount: computed(() => children.filter(child => child.getExposed?.()?.isChecked.value).length),
|
||||
isFull: computed(() => {
|
||||
const selectedCount = children.filter(child => child.getExposed?.()?.isChecked.value).length;
|
||||
return props.max && selectedCount >= props.max;
|
||||
}),
|
||||
isEmpty: computed(() => children.filter(child => child.getExposed?.()?.isChecked.value).length === 0),
|
||||
// 工具方法
|
||||
getChildrenCount: () => children.length
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../libs/css/style.components.scss';
|
||||
|
||||
.u-checkbox-group {
|
||||
/* #ifndef MP || APP-NVUE */
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user