chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<view class="l-checkbox-group" :class="'l-checkbox-group--'+ direction">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts" setup>
|
||||
/**
|
||||
* CheckboxGroup 复选框组容器
|
||||
* @description 用于管理多个 Checkbox 组件,支持整体禁用、最大选择和布局控制
|
||||
* <br> 插件类型:LCheckboxGroupComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-checkbox-group
|
||||
*
|
||||
* @property {Boolean} disabled 是否禁用组件
|
||||
* @property {Boolean} readonly 是否只读组件
|
||||
* @property {Number} max 支持最多选中的数量
|
||||
* @property {String|Number} name 唯一标识
|
||||
* @property {String|Number} value 选中值
|
||||
* @property {'small' | 'medium' | 'large'} size 组件统一尺寸
|
||||
* @value small
|
||||
* @value medium
|
||||
* @value large
|
||||
* @property {String} direction 布局方向
|
||||
* @value horizontal 水平
|
||||
* @value vertical 垂直
|
||||
* @property {String} icon = [square|round|circle] 形状
|
||||
* @value circle icon 圆形
|
||||
* @value line icon 线
|
||||
* @value rectangle icon 方形
|
||||
* @value dot icon 点状
|
||||
* @property {string} fontSize 文本统一字号
|
||||
* @property {string} iconSize 图标统一尺寸
|
||||
* @property {string} checkedColor 选中状态主题色
|
||||
* @property {string} iconBgColor 图标背景色
|
||||
* @property {string} iconBorderColor 图标边框色
|
||||
* @property {string} iconDisabledColor 禁用图标颜色
|
||||
* @property {string} iconDisabledBgColor 禁用背景色
|
||||
* @event {Function} change
|
||||
*/
|
||||
|
||||
import type { CheckboxGroupProps } from './type';
|
||||
import type { CheckboxChangeOptions } from '../l-checkbox/type';
|
||||
import { setCheckAllStatus } from './utils';
|
||||
|
||||
const emit = defineEmits(['update:value', 'update:modelValue', 'change']);
|
||||
const props = withDefaults(defineProps<CheckboxGroupProps>(), {
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
size: 'medium',
|
||||
direction: 'horizontal',
|
||||
icon: 'rectangle'
|
||||
})
|
||||
|
||||
const _innerValue = ref(props.defaultValue ?? [])
|
||||
const innerValue = computed({
|
||||
set(value: any[]){
|
||||
_innerValue.value = value
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
emit('update:modelValue', value)
|
||||
},
|
||||
get(): any[]{
|
||||
return props.value ?? props.modelValue ?? _innerValue.value
|
||||
},
|
||||
} as WritableComputedOptions<any[]>)
|
||||
|
||||
const checkedSet = computed(():Set<any>=>{
|
||||
const set = new Set<any>()
|
||||
if (Array.isArray(innerValue.value)) {
|
||||
innerValue.value.forEach(item => {
|
||||
set.add(item)
|
||||
})
|
||||
}
|
||||
return set
|
||||
});
|
||||
const children = reactive<LCheckboxComponentPublicInstance[]>([]);
|
||||
// @ts-ignore
|
||||
const checkAllStatus = setCheckAllStatus(children, innerValue, checkedSet);
|
||||
const maxExceeded = computed(():boolean => {
|
||||
return props.max != null && innerValue.value.length == props.max;
|
||||
});
|
||||
|
||||
const manageChildInList = (child: LCheckboxComponentPublicInstance, shouldAdd: boolean) => {
|
||||
const index = children.indexOf(child);
|
||||
if(shouldAdd) {
|
||||
if(index != -1) return
|
||||
children.push(child)
|
||||
} else {
|
||||
if(index == -1) return
|
||||
children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
const handleCheckboxChange = (item: CheckboxChangeOptions) => {
|
||||
const currentValue = item.value;
|
||||
if(Array.isArray(innerValue.value)) {
|
||||
if(currentValue == null) return;
|
||||
const val = [...innerValue.value];
|
||||
if (item.checked) {
|
||||
val.push(currentValue);
|
||||
} else {
|
||||
const i = val.indexOf(currentValue);
|
||||
val.splice(i, 1);
|
||||
}
|
||||
innerValue.value = val
|
||||
} else {
|
||||
console.warn(`CheckboxGroup Warn: \`value\` must be an array, instead of ${typeof innerValue.value}`);
|
||||
}
|
||||
}
|
||||
const getAllCheckboxValue = () : any[] => {
|
||||
const arr:any[] = []
|
||||
for (let i = 0, len = children.length; i < len; i++) {
|
||||
const item = children[i];
|
||||
const value = item.value ?? item.name //?? item.$.uid;
|
||||
if (item.checkAll) continue;
|
||||
if (value == null) continue;
|
||||
if(arr.includes(value)) continue;
|
||||
arr.push(value)
|
||||
if (maxExceeded.value) break;
|
||||
}
|
||||
return arr
|
||||
};
|
||||
const toggleAllCheckboxValues = () : any[] => {
|
||||
const arr:any[] = []
|
||||
|
||||
for (let i = 0, len = children.length; i < len; i++) {
|
||||
const item = children[i];
|
||||
const value = item.value ?? item.name;
|
||||
|
||||
if (item.checkAll) continue;
|
||||
if (value == null) continue;
|
||||
if(!checkedSet.value.has(value)) {
|
||||
arr.push(value)
|
||||
};
|
||||
if (maxExceeded.value) break;
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
const onCheckAllChange = (checked: boolean) => {
|
||||
const value = checked ? getAllCheckboxValue() : [];
|
||||
innerValue.value = value;
|
||||
}
|
||||
|
||||
const onCheckedChange = (item: CheckboxChangeOptions) => {
|
||||
if(item.checkAll) {
|
||||
onCheckAllChange(item.checked);
|
||||
} else {
|
||||
handleCheckboxChange(item);
|
||||
}
|
||||
}
|
||||
|
||||
const toggleAll = (checked : boolean) => {
|
||||
const value = checked ? getAllCheckboxValue() : toggleAllCheckboxValues();
|
||||
innerValue.value = value
|
||||
}
|
||||
|
||||
|
||||
defineExpose({
|
||||
toggleAll
|
||||
})
|
||||
|
||||
provide('limeCheckboxGroup', props)
|
||||
provide('limeCheckboxGroupValue', innerValue)
|
||||
provide('limeCheckboxGroupStatus', checkAllStatus)
|
||||
provide('limeCheckboxGroupCheckedSet', checkedSet)
|
||||
provide('limeCheckboxGroupManageChildInList', manageChildInList)
|
||||
provide('limeCheckboxGroupOnCheckedChange', onCheckedChange)
|
||||
// const optionList = getOptions(props, children);
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-checkbox-group {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.l-checkbox-group--vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<view class="l-checkbox-group" :class="'l-checkbox-group--'+ direction">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* CheckboxGroup 复选框组容器
|
||||
* @description 用于管理多个 Checkbox 组件,支持整体禁用、最大选择和布局控制
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-checkbox-group
|
||||
*
|
||||
* @property {Boolean} disabled 是否禁用组件
|
||||
* @property {Boolean} readonly 是否只读组件
|
||||
* @property {Number} max 支持最多选中的数量
|
||||
* @property {String|Number} name 唯一标识
|
||||
* @property {String|Number} value 选中值
|
||||
* @property {'small' | 'medium' | 'large'} size 组件统一尺寸
|
||||
* @value small
|
||||
* @value medium
|
||||
* @value large
|
||||
* @property {String} direction 布局方向
|
||||
* @value horizontal 水平
|
||||
* @value vertical 垂直
|
||||
* @property {String} icon = [square|round|circle] 形状
|
||||
* @value circle icon 圆形
|
||||
* @value line icon 线
|
||||
* @value rectangle icon 方形
|
||||
* @value dot icon 点状
|
||||
* @property {string} fontSize 文本统一字号
|
||||
* @property {string} iconSize 图标统一尺寸
|
||||
* @property {string} checkedColor 选中状态主题色
|
||||
* @property {string} iconBgColor 图标背景色
|
||||
* @property {string} iconBorderColor 图标边框色
|
||||
* @property {string} iconDisabledColor 禁用图标颜色
|
||||
* @property {string} iconDisabledBgColor 禁用背景色
|
||||
* @event {Function} change
|
||||
*/
|
||||
|
||||
import { defineComponent, provide, ref, computed, reactive } from '@/uni_modules/lime-shared/vue';
|
||||
import checkboxGroupProps from './props'
|
||||
import type { CheckboxGroupProps } from './type';
|
||||
import type { CheckboxChangeOptions } from '../l-checkbox/type';
|
||||
import { setCheckAllStatus } from './utils';
|
||||
|
||||
const name = 'l-checkbox-group'
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: checkboxGroupProps,
|
||||
emits: ['update:value', 'update:modelValue', 'change', 'input'],
|
||||
setup(props, { emit, expose }) {
|
||||
const _innerValue = ref(props.defaultValue ?? [])
|
||||
const innerValue = computed({
|
||||
set(value: any[]){
|
||||
_innerValue.value = value
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
emit('update:modelValue', value)
|
||||
// #ifdef VUE2
|
||||
emit('input', value)
|
||||
// #endif
|
||||
},
|
||||
get(): any[]{
|
||||
return props.value ?? props.modelValue ?? _innerValue.value
|
||||
},
|
||||
} as WritableComputedOptions<any[]>)
|
||||
|
||||
const checkedSet = computed(():Set<any>=>{
|
||||
const set = new Set<any>()
|
||||
if (Array.isArray(innerValue.value)) {
|
||||
innerValue.value.forEach(item => {
|
||||
set.add(item)
|
||||
})
|
||||
}
|
||||
return set
|
||||
});
|
||||
const children = reactive<LCheckboxComponentPublicInstance[]>([]);
|
||||
// @ts-ignore
|
||||
const checkAllStatus = setCheckAllStatus(children, innerValue, checkedSet);
|
||||
const maxExceeded = computed(():boolean => {
|
||||
return props.max != null && innerValue.value.length == props.max;
|
||||
});
|
||||
|
||||
const manageChildInList = (child: LCheckboxComponentPublicInstance, shouldAdd: boolean) => {
|
||||
const index = children.indexOf(child);
|
||||
if(shouldAdd) {
|
||||
if(index != -1) return
|
||||
children.push(child)
|
||||
} else {
|
||||
if(index == -1) return
|
||||
children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
const handleCheckboxChange = (item: CheckboxChangeOptions) => {
|
||||
const currentValue = item.value;
|
||||
if(Array.isArray(innerValue.value)) {
|
||||
if(currentValue == null) return;
|
||||
const val = [...innerValue.value];
|
||||
if (item.checked) {
|
||||
val.push(currentValue);
|
||||
} else {
|
||||
const i = val.indexOf(currentValue);
|
||||
val.splice(i, 1);
|
||||
}
|
||||
innerValue.value = val
|
||||
} else {
|
||||
console.warn(`CheckboxGroup Warn: \`value\` must be an array, instead of ${typeof innerValue.value}`);
|
||||
}
|
||||
}
|
||||
const getAllCheckboxValue = () : any[] => {
|
||||
const arr:any[] = []
|
||||
for (let i = 0, len = children.length; i < len; i++) {
|
||||
const item = children[i];
|
||||
const value = item.value ?? item.name //?? item.$.uid;
|
||||
if (item.checkAll) continue;
|
||||
if (value == null) continue;
|
||||
if(arr.includes(value)) continue;
|
||||
arr.push(value)
|
||||
if (maxExceeded.value) break;
|
||||
}
|
||||
return arr
|
||||
};
|
||||
const toggleAllCheckboxValues = () : any[] => {
|
||||
const arr:any[] = []
|
||||
|
||||
for (let i = 0, len = children.length; i < len; i++) {
|
||||
const item = children[i];
|
||||
const value = item.value ?? item.name;
|
||||
|
||||
if (item.checkAll) continue;
|
||||
if (value == null) continue;
|
||||
if(!checkedSet.value.has(value)) {
|
||||
arr.push(value)
|
||||
};
|
||||
if (maxExceeded.value) break;
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
const onCheckAllChange = (checked: boolean) => {
|
||||
const value = checked ? getAllCheckboxValue() : [];
|
||||
innerValue.value = value;
|
||||
}
|
||||
|
||||
const onCheckedChange = (item: CheckboxChangeOptions) => {
|
||||
if(item.checkAll) {
|
||||
onCheckAllChange(item.checked);
|
||||
} else {
|
||||
handleCheckboxChange(item);
|
||||
}
|
||||
}
|
||||
|
||||
const toggleAll = (checked : boolean) => {
|
||||
const value = checked ? getAllCheckboxValue() : toggleAllCheckboxValues();
|
||||
innerValue.value = value
|
||||
}
|
||||
|
||||
// #ifdef VUE3
|
||||
expose({
|
||||
toggleAll
|
||||
})
|
||||
// #endif
|
||||
provide('limeCheckboxGroup', props)
|
||||
provide('limeCheckboxGroupValue', innerValue)
|
||||
provide('limeCheckboxGroupStatus', checkAllStatus)
|
||||
provide('limeCheckboxGroupCheckedSet', checkedSet)
|
||||
provide('limeCheckboxGroupManageChildInList', manageChildInList)
|
||||
provide('limeCheckboxGroupOnCheckedChange', onCheckedChange)
|
||||
|
||||
return {
|
||||
// #ifdef VUE2
|
||||
toggleAll
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-checkbox-group {
|
||||
// background-color: antiquewhite;
|
||||
}
|
||||
|
||||
.l-checkbox-group--vertical {
|
||||
:deep(.l-checkbox) {
|
||||
display: flex;
|
||||
// line-height: 64rpx;
|
||||
}
|
||||
|
||||
:deep(l-checkbox) {
|
||||
display: flex;
|
||||
// line-height: 64rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,81 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
/** 是否禁用组件,默认为 false。CheckboxGroup.disabled 优先级低于 Checkbox.disabled */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 支持最多选中的数量 */
|
||||
max: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
/** 唯一标识 */
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
/** 选中值 */
|
||||
value: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
/** 选中值,非受控属性 */
|
||||
defaultValue: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal'
|
||||
},
|
||||
// 未实现
|
||||
/** 以配置形式设置子元素。示例1:`['北京', '上海']` ,示例2: `[{ label: '全选', checkAll: true }, { label: '上海', value: 'shanghai' }]`。checkAll 值为 true 表示当前选项为「全选选项」 */
|
||||
options: {
|
||||
type: Array,
|
||||
},
|
||||
checkedColor: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
iconBgColor: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
iconBorderColor: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
iconDisabledColor: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
iconDisabledBgColor: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'rectangle'
|
||||
}, //?: 'circle' | 'line' | 'dot';
|
||||
size: {
|
||||
type: String,
|
||||
default: 'medium'
|
||||
}, //?: 'small' | 'medium' | 'large';
|
||||
iconSize: {
|
||||
type: String,
|
||||
defalut: null
|
||||
},
|
||||
fontSize: {
|
||||
type: String,
|
||||
defalut: null
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
export type CheckerDirection = 'horizontal' | 'vertical';
|
||||
export type CheckboxGroupValue = any[]//Array<string | number | boolean>;
|
||||
|
||||
export interface CheckboxGroupProps {
|
||||
/** 是否禁用组件,默认为 false。CheckboxGroup.disabled 优先级低于 Checkbox.disabled */
|
||||
disabled : boolean;
|
||||
readonly : boolean;
|
||||
/** 支持最多选中的数量 */
|
||||
max?: number;
|
||||
/** 唯一标识 */
|
||||
name?: any;//string;
|
||||
/** 选中值 */
|
||||
value?: any[];
|
||||
modelValue?: any[];
|
||||
/** 选中值,非受控属性 */
|
||||
defaultValue?: any[];
|
||||
|
||||
size: 'small' | 'medium' | 'large';
|
||||
direction : CheckerDirection;
|
||||
gap?: string;
|
||||
icon: 'circle' | 'line' | 'rectangle' | 'dot';
|
||||
|
||||
//未实现
|
||||
// options: Array<unknown>,
|
||||
fontSize?: string;
|
||||
iconSize?: string;
|
||||
checkedColor?: string;
|
||||
iconBgColor?: string;
|
||||
iconBorderColor?: string;
|
||||
iconDisabledColor?: string;
|
||||
iconDisabledBgColor?: string;
|
||||
}
|
||||
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
export type {ComputedRef} from 'vue';
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
export type ComputedRef<T> = ComputedRefImpl<T>;
|
||||
// #endif
|
||||
@@ -0,0 +1,64 @@
|
||||
// @ts-nocheck
|
||||
import type { ComputedRef } from './type';
|
||||
import type { CheckboxStatus } from '../l-checkbox/type';
|
||||
// #ifndef UNI-APP-X
|
||||
import { computed } from '@/uni_modules/lime-shared/vue';
|
||||
// #endif
|
||||
|
||||
function intersection<T>(...arrays : T[][]): T[] {
|
||||
// 创建一个空数组来存储相交元素
|
||||
const result : T[] = [];
|
||||
|
||||
for (let i = 0; i < arrays[0].length; i++) {
|
||||
const item = arrays[0][i]
|
||||
// 检查该元素是否存在于所有其他数组中
|
||||
let isCommon = true;
|
||||
for (let j = 1; j < arrays.length; j++) {
|
||||
if (!arrays[j].includes(item)) {
|
||||
isCommon = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果该元素存在于所有数组中,并且尚未添加到结果数组中,则将其添加到结果数组中
|
||||
if (isCommon && !result.includes(item)) {
|
||||
result.push(item);
|
||||
}
|
||||
}
|
||||
// 返回包含相交元素的结果数组
|
||||
return result;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
export function setCheckAllStatus(
|
||||
children: LCheckboxComponentPublicInstance[],
|
||||
innerValue: ComputedRef<any[]>,
|
||||
checkedSet: ComputedRef<Set<any>>
|
||||
): ComputedRef<CheckboxStatus> {
|
||||
|
||||
const intersectionLen = computed(()=>{
|
||||
const values:any[] = []
|
||||
children.forEach(item => {
|
||||
const value = item.value ?? item.name;
|
||||
if(value == null) return
|
||||
values.push(value)
|
||||
})
|
||||
if (Array.isArray(innerValue.value)) {
|
||||
return intersection(innerValue.value, values).length;
|
||||
}
|
||||
return 0
|
||||
})
|
||||
const isAllChecked = computed((): boolean=>{
|
||||
if (checkedSet.value.size != children.length - 1) {
|
||||
return false;
|
||||
}
|
||||
return intersectionLen.value == children.length - 1;
|
||||
})
|
||||
const isIndeterminate = computed((): boolean=>{
|
||||
return !isAllChecked.value && intersectionLen.value < children.length && intersectionLen.value > 0;
|
||||
})
|
||||
return computed(():CheckboxStatus => {
|
||||
if (isAllChecked.value) return 'checked';
|
||||
if (isIndeterminate.value) return 'indeterminate';
|
||||
return 'uncheck';
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user