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';
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
@import '~@/uni_modules/lime-style/index.scss';
|
||||
@import '~@/uni_modules/lime-style/functions.scss';
|
||||
/* #ifdef uniVersion >= 4.75 */
|
||||
$use-css-var: true !default;
|
||||
/* #endif */
|
||||
|
||||
$checkbox: #{$prefix}-checkbox;
|
||||
$icon: #{$checkbox}__icon;
|
||||
|
||||
|
||||
$checkbox-icon-size: create-var(checkbox-icon-size, 20px);
|
||||
$checkbox-font-size: create-var(checkbox-font-size, 16px);
|
||||
|
||||
$checkbox-small-icon-size: create-var(checkbox-small-icon-size, 14px);
|
||||
$checkbox-small-font-size: create-var(checkbox-small-font-size, 15px);
|
||||
|
||||
$checkbox-large-icon-size: create-var(checkbox-large-icon-size, 22px);
|
||||
$checkbox-large-font-size: create-var(checkbox-large-font-size, 18px);
|
||||
|
||||
$checkbox-icon-border-width: create-var(checkbox-icon-border-width, 1px);
|
||||
// $checkbox-icon-border-color: var(--l-checkbox-border-color, $border-color);
|
||||
$checkbox-icon-border-radius: create-var(checkbox-icon-border-radius, 3px);
|
||||
|
||||
$checkbox-icon-bg-color: create-var(checkbox-icon-bg-color, $bg-color-container);
|
||||
$checkbox-icon-border-color: create-var(checkbox-border-icon-color, $gray-5);
|
||||
$checkbox-icon-disabled-color: create-var(checkbox-icon-disabled-color, $gray-5);
|
||||
$checkbox-icon-disabled-bg-color: create-var(checkbox-icon-disabled-bg-color, $gray-1);
|
||||
$checkbox-icon-checked-color: create-var(checkbox-icon-checked-color, $primary-color);
|
||||
$checkbox-text-color: create-var(checkbox-text-color, $text-color-1);
|
||||
$checkbox-icon-text-gap: create-var(checkbox-icon-text-gap, $spacer-xs);
|
||||
|
||||
/* #ifdef MP */
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
/* #endif */
|
||||
.#{$checkbox} {
|
||||
/* #ifndef UNI-APP-X */
|
||||
display: inline-flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
&__icon {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: $checkbox-icon-size;
|
||||
height: $checkbox-icon-size;
|
||||
align-self: center;
|
||||
transition-property: all;
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// #ifndef APP-HARMONY || APP-ANDROID
|
||||
// 鸿蒙加上时间会导致无法描边 安卓会没有尺寸
|
||||
transition-duration: 200ms;
|
||||
/* #endif */
|
||||
/* #endif */
|
||||
transition-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
opacity: 0;
|
||||
content: "";
|
||||
transition-property: all;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
}
|
||||
/* #endif */
|
||||
&--rectangle {
|
||||
// border-radius: $checkbox-icon-border-radius;
|
||||
@include border-radius($checkbox-icon-border-radius);
|
||||
}
|
||||
&--dot,
|
||||
&--circle {
|
||||
border-radius: 99px;
|
||||
}
|
||||
&--rectangle,
|
||||
&--dot,
|
||||
&--circle{
|
||||
background-color: $checkbox-icon-bg-color;
|
||||
border-width: $checkbox-icon-border-width;
|
||||
border-style: solid;
|
||||
border-color: $checkbox-icon-border-color;
|
||||
// border: $checkbox-icon-border-width solid $checkbox-icon-border-color;
|
||||
}
|
||||
&--rectangle,&--circle {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
top: 48%;
|
||||
left: 24%;
|
||||
display: table;
|
||||
width: divide(100%, 20) * 7;
|
||||
height: divide(100%, 20) * 12;
|
||||
border: calc(#{$checkbox-icon-size} / 7) solid transparent;
|
||||
border-top: 0;
|
||||
border-inline-start: 0;
|
||||
transform: rotate(45deg) scale(0) translate(-50%,-50%);
|
||||
content: "";
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--rectangle#{&}--checked,
|
||||
&--circle#{&}--checked {
|
||||
background-color: $checkbox-icon-checked-color;
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg) scale(1) translate(-50%,-50%);
|
||||
border-color: white;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--rectangle#{&}--indeterminate,
|
||||
&--circle#{&}--indeterminate{
|
||||
background-color: $checkbox-icon-checked-color;
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
opacity: 1;
|
||||
height: 0;
|
||||
width: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: scale(1) translate(-50%,-50%);
|
||||
border-color: white;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
&--dot {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
background-color: white;
|
||||
border-radius: 99px;//$checkbox-icon-border-radius;
|
||||
transform: scale(0) translate(-50%,-50%);
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--dot#{&}--checked{
|
||||
background-color: $checkbox-icon-checked-color;
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after{
|
||||
opacity: 1;
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
transform: scale(1) translate(-50%,-50%);
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--dot#{&}--indeterminate {
|
||||
background-color: $checkbox-icon-checked-color;
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
opacity: 1;
|
||||
border-radius: 0;
|
||||
transform: scale(1) translate(-50%,-50%);
|
||||
width: 50%;
|
||||
height: calc(#{$checkbox-icon-size} / 7);
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--line {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
top: 46%;
|
||||
left: 0%;
|
||||
inset-inline-start: 10%;
|
||||
display: table;
|
||||
width: divide(100%, 14) * 7;
|
||||
height: divide(100%, 14) * 12;
|
||||
border: calc(#{$checkbox-icon-size} / 7) solid transparent;
|
||||
border-top: 0;
|
||||
border-inline-start: 0;
|
||||
transform: rotate(45deg) scale(0) translate(-50%,-50%);
|
||||
content: "";
|
||||
transition-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--line#{&}--checked {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg) scale(1) translate(-50%,-50%);
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--line#{&}--indeterminate {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
opacity: 1;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
width: 70%;
|
||||
transform: scale(1) translate(-50%,-50%);
|
||||
border-color: $checkbox-icon-checked-color;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
&--rectangle#{&}--disabled,
|
||||
&--circle#{&}--disabled,
|
||||
&--dot#{&}--disabled {
|
||||
border-color: $checkbox-icon-disabled-color;
|
||||
background-color: $checkbox-icon-disabled-bg-color;
|
||||
}
|
||||
&--rectangle#{&}--disabled#{&}--checked,
|
||||
&--circle#{&}--disabled#{&}--checked,
|
||||
&--dot#{&}--disabled#{&}--checked,
|
||||
&--rectangle#{&}--disabled#{&}--indeterminate,
|
||||
&--circle#{&}--disabled#{&}--indeterminate,
|
||||
&--dot#{&}--disabled#{&}--indeterminate {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
border-color: $checkbox-icon-disabled-color;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--dot#{&}--disabled#{&}--checked,
|
||||
&--dot#{&}--disabled#{&}--indeterminate {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
background-color: $checkbox-icon-disabled-color;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--line#{&}--disabled#{&}--checked,
|
||||
&--line#{&}--disabled#{&}--indeterminate{
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
&:after {
|
||||
border-color: $checkbox-icon-disabled-color;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
&__label {
|
||||
padding-left: $checkbox-icon-text-gap;//$spacer-xs;
|
||||
// padding-right: $spacer-xs;
|
||||
font-size: $checkbox-font-size;
|
||||
color: $checkbox-text-color;//$text-color-1;
|
||||
white-space: nowrap; //ios
|
||||
&--disabled {
|
||||
color: $checkbox-icon-disabled-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<view class="l-checkbox" :class="[rootCasses]" :style="[styles]" @click="handleChange">
|
||||
<slot name="checkbox" :checked="isChecked" :disabled="isDisabled">
|
||||
<slot name="icon" :checked="isChecked" :disabled="isDisabled">
|
||||
<view class="l-checkbox__icon" ref="iconRef"
|
||||
:class="[
|
||||
`l-checkbox__icon--${icon}`,
|
||||
{
|
||||
'l-checkbox__icon--checked': isChecked,
|
||||
'l-checkbox__icon--disabled': isDisabled,
|
||||
'l-checkbox__icon--indeterminate': isIndeterminate,
|
||||
}
|
||||
]" :style="[iconStyle]"></view>
|
||||
</slot>
|
||||
<text class="l-checkbox__label" :style="[labelStyles]" :class="labelClass" v-if="label!= null || $slots['default'] !=null">
|
||||
<slot>{{label}}</slot>
|
||||
</text>
|
||||
</slot>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
/**
|
||||
* Checkbox 复选框组件
|
||||
* @description 用于在多个选项中进行选择的表单组件,支持单选、全选和不确定态
|
||||
* <br> 插件类型:LCheckboxComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-checkbox
|
||||
*
|
||||
* @property {boolean} defaultChecked 默认选中状态(非受控属性)
|
||||
* @property {string} label 显示文本(支持插槽)
|
||||
* @property {boolean} indeterminate 半选状态(优先级高于checked)
|
||||
* @property {boolean} disabled 禁用状态(覆盖Group设置)
|
||||
* @property {'small' | 'medium' | 'large'} size 组件尺寸
|
||||
* @value small
|
||||
* @value medium
|
||||
* @value large
|
||||
* @property {string} name 唯一标识符(表单提交使用)
|
||||
* @property {boolean} checkAll 标记为全选选项(需在Group中使用)
|
||||
* @property {string} value 选项值(Group模式下必填)
|
||||
* @property {'circle' | 'line' | 'rectangle' | 'dot'} icon 图标样式类型
|
||||
* @value circle 圆
|
||||
* @value line 线
|
||||
* @value rectangle 方
|
||||
* @value dot 点
|
||||
* @property {string} fontSize 文本字号(支持CSS单位)
|
||||
* @property {string} iconSize 图标尺寸(支持CSS单位)
|
||||
* @property {string} checkedColor 选中状态主题色
|
||||
* @property {string} iconBgColor 图标背景色
|
||||
* @property {string} iconBorderColor 图标边框色
|
||||
* @property {string} iconDisabledColor 禁用状态图标颜色
|
||||
* @property {string} iconDisabledBgColor 禁用状态背景色
|
||||
* @property {string|object} labelStyle label的样式
|
||||
* @event {Function} change 状态变化时触发(参数:CheckboxChangeOptions)
|
||||
*/
|
||||
|
||||
import type { CheckboxProps, ManageChildInList, CheckboxStatus, OnCheckedChange, CheckboxChangeOptions, ComputedRef } from './type';
|
||||
// import { isDarkMode, themeTokens } from '@/uni_modules/lime-style'
|
||||
const themeVars = inject('limeConfigProviderThemeVars', computed(()=> ({})))
|
||||
defineSlots<{
|
||||
checkbox(props : { checked : boolean, disabled: boolean}) : any,
|
||||
icon(props : { checked : boolean, disabled: boolean}) : any,
|
||||
default(props : { checked : boolean, disabled: boolean}) : any,
|
||||
}>()
|
||||
|
||||
|
||||
const name = 'l-checkbox';
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const props = withDefaults(defineProps<CheckboxProps>(), {
|
||||
defaultChecked: false,
|
||||
indeterminate: false,
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
// checked: null,
|
||||
// modelValue: null,
|
||||
size: 'medium',
|
||||
checkAll: false,
|
||||
icon: 'rectangle'
|
||||
})
|
||||
|
||||
defineOptions({
|
||||
mixins: [{
|
||||
props: {
|
||||
checked: {
|
||||
type: [null, Boolean],
|
||||
default: null,
|
||||
},
|
||||
modelValue: {
|
||||
type: [null, Boolean],
|
||||
default: null,
|
||||
},
|
||||
}
|
||||
}]
|
||||
})
|
||||
|
||||
|
||||
const instance = getCurrentInstance()!
|
||||
const formDisabled = inject<Ref<boolean|null>|null>('formDisabled', null)
|
||||
const formReadonly = inject<Ref<boolean|null>|null>('formReadonly', null)
|
||||
|
||||
const checkboxGroup = inject<LCheckboxGroupComponentPublicInstance|null>('limeCheckboxGroup', null);
|
||||
const checkboxGroupValue = inject<ComputedRef<any[]>|null>('limeCheckboxGroupValue', null);
|
||||
const checkboxGroupStatus = inject<ComputedRef<CheckboxStatus>|null>('limeCheckboxGroupStatus', null);
|
||||
const checkboxGroupCheckedSet = inject<ComputedRef<Set<any>>|null>('limeCheckboxGroupCheckedSet', null);
|
||||
const manageChildInList = inject<ManageChildInList|null>('limeCheckboxGroupManageChildInList', null);
|
||||
const onCheckedChange = inject<OnCheckedChange|null>('limeCheckboxGroupOnCheckedChange', null);
|
||||
if(manageChildInList != null) {
|
||||
manageChildInList(instance.proxy as LCheckboxComponentPublicInstance, true)
|
||||
}
|
||||
|
||||
const max = computed(():number => checkboxGroup?.max ?? -1)
|
||||
|
||||
const _innerChecked = ref(props.defaultChecked)
|
||||
const innerChecked = computed({
|
||||
set(value: boolean) {
|
||||
_innerChecked.value = value
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value)
|
||||
},
|
||||
get():boolean {
|
||||
const value = (props.checked ?? props.modelValue)
|
||||
if(value != null) return value
|
||||
return _innerChecked.value
|
||||
}
|
||||
} as WritableComputedOptions<boolean>)
|
||||
|
||||
const isChecked = computed(():boolean=>{
|
||||
if (props.checkAll) {
|
||||
const checkAllStatus = checkboxGroupStatus?.value ?? 'uncheck';
|
||||
return checkAllStatus == 'checked' || checkAllStatus == 'indeterminate'
|
||||
}
|
||||
const value = props.value ?? props.name;
|
||||
if (checkboxGroupCheckedSet != null && value != null) {
|
||||
return checkboxGroupCheckedSet.value.has(value)
|
||||
}
|
||||
return innerChecked.value;
|
||||
})
|
||||
|
||||
const isDisabled = computed(():boolean=>{
|
||||
if(max.value > -1 && checkboxGroupValue != null) {
|
||||
return max.value <= checkboxGroupValue.value.length && !isChecked.value;
|
||||
}
|
||||
if (props.disabled) return props.disabled;
|
||||
return formDisabled?.value ?? checkboxGroup?.disabled ?? false;
|
||||
})
|
||||
|
||||
const isReadonly= computed(():boolean=>{
|
||||
if (props.readonly) return props.readonly;
|
||||
return formReadonly?.value ?? checkboxGroup?.readonly ?? false;
|
||||
})
|
||||
|
||||
const isIndeterminate = computed(():boolean=>{
|
||||
if (props.checkAll && checkboxGroupStatus != null) return checkboxGroupStatus.value == 'indeterminate';
|
||||
return props.indeterminate;
|
||||
})
|
||||
|
||||
const innerIcon = computed(():string => checkboxGroup?.icon ?? props.icon)
|
||||
const innerSize = computed(():string => checkboxGroup?.size ?? props.size)
|
||||
const innerIconSize = computed(():string|null => checkboxGroup?.iconSize ?? props.iconSize)
|
||||
const innerFontSize = computed(():string|null => checkboxGroup?.fontSize ?? props.fontSize)
|
||||
const innerCheckedColor = computed(():string|null => checkboxGroup?.checkedColor ?? props.checkedColor)
|
||||
const innerIconBgColor = computed(():string|null => props.iconBgColor ?? checkboxGroup?.iconBgColor)
|
||||
const innerIconBorderColor = computed(():string|null => props.iconBorderColor ?? checkboxGroup?.iconBorderColor )
|
||||
const innerIconDisabledColor = computed(():string|null => props.iconDisabledColor ?? checkboxGroup?.iconDisabledColor )
|
||||
const innerIconDisabledBgColor = computed(():string|null => props.iconDisabledBgColor ?? checkboxGroup?.iconDisabledBgColor)
|
||||
|
||||
|
||||
const rootCasses = computed(():Map<string, boolean>=>{
|
||||
const cls = new Map<string, boolean>()
|
||||
cls.set(`${name}--${props.size}`, true)
|
||||
cls.set(`${name}--disabled`, isDisabled.value)
|
||||
return cls
|
||||
})
|
||||
|
||||
const iconClasses = computed(():Map<string, boolean>=>{
|
||||
const cls = new Map<string, boolean>()
|
||||
cls.set(`${name}__icon--disabled`, isDisabled.value)
|
||||
cls.set(`${name}__icon--${props.icon}`, true)
|
||||
// #ifdef APP
|
||||
cls.set(`${name}__icon--checked`, isChecked.value && innerCheckedColor.value == null)
|
||||
cls.set(`${name}__icon--indeterminate`, isIndeterminate.value && innerCheckedColor.value == null)
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
cls.set(`${name}__icon--checked`, isChecked.value)
|
||||
cls.set(`${name}__icon--indeterminate`, isIndeterminate.value)
|
||||
// #endif
|
||||
return cls
|
||||
})
|
||||
|
||||
const labelClass = computed(():Map<string, boolean>=>{
|
||||
const cls = new Map<string, boolean>();
|
||||
cls.set(`${name}__label--disabled`, isDisabled.value)
|
||||
return cls
|
||||
})
|
||||
|
||||
const styles = computed(():Map<string, any>=>{
|
||||
const style = new Map<string, any>();
|
||||
if(checkboxGroup != null && checkboxGroup.gap != null) {
|
||||
style.set(checkboxGroup.direction == 'horizontal' ? 'margin-right' : 'margin-bottom', checkboxGroup.gap!)
|
||||
}
|
||||
// #ifndef APP
|
||||
if(innerCheckedColor.value != null) {
|
||||
style.set('--l-checkbox-icon-checked-color', innerCheckedColor.value!)
|
||||
}
|
||||
if(innerIconBorderColor.value != null) {
|
||||
style.set('--l-checkbox-icon-border-color', innerIconBorderColor.value!)
|
||||
}
|
||||
if(innerIconDisabledColor.value != null) {
|
||||
style.set('--l-checkbox-icon-disabled-color', innerIconDisabledColor.value!)
|
||||
}
|
||||
if(innerIconDisabledBgColor.value != null) {
|
||||
style.set('--l-checkbox-icon-disabled-bg-color', innerIconDisabledBgColor.value!)
|
||||
}
|
||||
if(innerFontSize.value != null) {
|
||||
style.set('--l-checkbox-font-size', innerFontSize.value!)
|
||||
}
|
||||
// #endif
|
||||
return style
|
||||
})
|
||||
|
||||
const iconStyle = computed(():Map<string, any>=>{
|
||||
const style = new Map<string, any>();
|
||||
if(innerIconSize.value != null) {
|
||||
style.set('width', innerIconSize.value!)
|
||||
style.set('height', innerIconSize.value!)
|
||||
// #ifndef APP
|
||||
style.set('--l-checkbox-icon-size', innerIconSize.value!)
|
||||
// #endif
|
||||
}
|
||||
|
||||
if(innerCheckedColor.value != null) {
|
||||
// #ifndef APP
|
||||
style.set('--l-checkbox-icon-checked-color', innerCheckedColor.value!)
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
|
||||
if(!isDisabled.value && !isChecked.value && ['dot', 'circle', 'rectangle'].includes(innerIcon.value)) {
|
||||
if(innerIconBgColor.value!=null) {
|
||||
style.set('background-color', innerIconBgColor.value!)
|
||||
}
|
||||
if(innerIconBorderColor.value!=null) {
|
||||
style.set('border-color', innerIconBorderColor.value!)
|
||||
}
|
||||
}
|
||||
if(isDisabled.value && ['dot', 'circle', 'rectangle'].includes(innerIcon.value)) {
|
||||
if(innerIconDisabledBgColor.value!=null) {
|
||||
style.set('background-color', innerIconDisabledBgColor.value!)
|
||||
}
|
||||
if(innerIconDisabledColor.value!=null) {
|
||||
style.set('border-color', innerIconDisabledColor.value!)
|
||||
}
|
||||
|
||||
}
|
||||
if(isChecked.value && ['dot', 'circle', 'rectangle'].includes(innerIcon.value)) {
|
||||
style.set('background-color', innerCheckedColor.value!)
|
||||
style.set('border-color', innerCheckedColor.value!)
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
// const labelStyle = computed(():Map<string, any>=>{
|
||||
// const style = new Map<string, any>();
|
||||
// const fontSize = props.fontSize ?? checkboxGroup?.fontSize
|
||||
// if(fontSize != null) {
|
||||
// style.set('font-size', fontSize)
|
||||
// }
|
||||
// return style
|
||||
// })
|
||||
|
||||
const labelStyles = computed(():any => {
|
||||
if(typeof props.labelStyle == 'string') {
|
||||
return `${props.labelStyle};` + (innerIconSize.value != null ? `font-size: ${innerIconSize.value}`: '')
|
||||
}
|
||||
if(typeof props.labelStyle == 'object') {
|
||||
return UTSJSONObject.assign({}, (props.labelStyle??{}) as UTSJSONObject, innerFontSize.value != null ? {'font-size': innerFontSize.value}: {})
|
||||
}
|
||||
return {}
|
||||
})
|
||||
const handleChange = (e: UniPointerEvent) => {
|
||||
if (isDisabled.value || isReadonly.value) return;
|
||||
const value = !isChecked.value;
|
||||
innerChecked.value = value;
|
||||
|
||||
if(onCheckedChange != null) {
|
||||
onCheckedChange({
|
||||
checked: value,
|
||||
checkAll: props.checkAll,
|
||||
value: props.value ?? props.name //?? instance.uid
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef APP
|
||||
const iconRef = ref<UniElement|null>(null)
|
||||
|
||||
const update = () => {
|
||||
if(iconRef.value == null) return
|
||||
const ctx = iconRef.value!.getDrawableContext()!;
|
||||
const rect = iconRef.value!.getBoundingClientRect();
|
||||
// #ifndef APP-HARMONY
|
||||
const iconSize = rect.width
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
const iconSize = rect.width - 1.5
|
||||
// #endif
|
||||
|
||||
const x = iconSize / 2;
|
||||
const y = iconSize / 2;
|
||||
|
||||
|
||||
const primaryColor = `${themeVars.value['checkboxIconCheckedColor'] ?? '#3283ff'}`
|
||||
const disabledColor = `${themeVars.value['checkboxIconDisabledColor'] ?? '#c5c5c5'}`
|
||||
|
||||
ctx.reset();
|
||||
const drawIndeterminate = () => {
|
||||
ctx.strokeStyle = isDisabled.value
|
||||
? innerIconDisabledColor.value ?? disabledColor//themes.get(isDarkMode.value ? 'dark' :'light')!
|
||||
: innerIcon.value == 'line'
|
||||
? props.checkedColor ?? primaryColor //'#3283ff'
|
||||
: 'white';
|
||||
ctx.lineWidth = innerIcon.value == 'line' ? iconSize * 0.16 : iconSize * 0.12;
|
||||
const width = innerIcon.value == 'line' ? iconSize * 0.8 : iconSize * 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo((iconSize - width) / 2, iconSize * 0.5);
|
||||
ctx.lineTo((iconSize - width) / 2 + width, iconSize * 0.5);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
const drawCheckedIcon = () => {
|
||||
if (isDisabled.value) {
|
||||
ctx.strokeStyle = innerIconDisabledColor.value ?? disabledColor;
|
||||
ctx.fillStyle = innerIconDisabledColor.value ?? disabledColor;
|
||||
} else if (innerIcon.value == 'line') {
|
||||
ctx.strokeStyle = props.checkedColor ?? primaryColor //'#3283ff';
|
||||
} else {
|
||||
ctx.strokeStyle = 'white';
|
||||
ctx.fillStyle = 'white';
|
||||
}
|
||||
ctx.lineWidth = innerIcon.value == 'line' ? iconSize * 0.16 : iconSize * 0.12;
|
||||
ctx.lineCap = 'round';
|
||||
|
||||
if (innerIcon.value == 'circle' || innerIcon.value == 'rectangle') {
|
||||
ctx.beginPath();
|
||||
// #ifndef APP-HARMONY
|
||||
ctx.moveTo(iconSize * 0.2967, iconSize * 0.53);
|
||||
ctx.lineTo(iconSize * 0.4342, iconSize * 0.6675);
|
||||
ctx.lineTo(iconSize * 0.7092, iconSize * 0.3925);
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-HARMONY
|
||||
// 鸿蒙不支持lineCap
|
||||
ctx.moveTo(iconSize * 0.23, iconSize * 0.45);
|
||||
ctx.lineTo(iconSize * 0.44, iconSize * 0.6675);
|
||||
ctx.lineTo(iconSize * 0.73, iconSize * 0.3);
|
||||
// #endif
|
||||
|
||||
ctx.stroke();
|
||||
} else if (innerIcon.value == 'line') {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(iconSize * 0.10, iconSize * 0.5466);
|
||||
ctx.lineTo(iconSize * 0.3666, iconSize * 0.8134);
|
||||
ctx.lineTo(iconSize * 0.90, iconSize * 0.28);
|
||||
ctx.stroke();
|
||||
} else if (innerIcon.value == 'dot') {
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, iconSize * 0.22, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
};
|
||||
|
||||
if (isIndeterminate.value) {
|
||||
drawIndeterminate();
|
||||
}else if (isChecked.value) {
|
||||
drawCheckedIcon();
|
||||
}
|
||||
ctx.update();
|
||||
}
|
||||
|
||||
|
||||
const resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => {
|
||||
update()
|
||||
})
|
||||
|
||||
const stopWatch = watch(():UniElement|null => iconRef.value, (el:UniElement|null) => {
|
||||
if(el== null) return
|
||||
resizeObserver.observe(el)
|
||||
})
|
||||
|
||||
let init = ref(false)
|
||||
// 在list-view里一开始没有尺寸
|
||||
watchEffect(()=>{
|
||||
if(iconRef.value == null) return
|
||||
if(init.value) {
|
||||
update()
|
||||
return
|
||||
}
|
||||
iconRef.value?.getBoundingClientRectAsync()?.then(res=>{
|
||||
requestAnimationFrame(update)
|
||||
init.value = true
|
||||
});
|
||||
})
|
||||
|
||||
onBeforeUnmount(()=>{
|
||||
try {
|
||||
// 鸿蒙在hbx4.66 由导航返回时会报错
|
||||
stopWatch()
|
||||
resizeObserver.disconnect()
|
||||
} catch(err) {
|
||||
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
onBeforeUnmount(()=>{
|
||||
if(manageChildInList != null) {
|
||||
manageChildInList(instance.proxy as LCheckboxComponentPublicInstance, false)
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index-u';
|
||||
</style>
|
||||
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<view class="l-checkbox" :class="[rootCasses]" :style="[styles]" @click="handleChange">
|
||||
<slot name="checkbox" :checked="isChecked" :disabled="isDisabled">
|
||||
<slot name="icon" :checked="isChecked" :disabled="isDisabled">
|
||||
<view class="l-checkbox__icon" ref="iconRef" :class="iconClasses" :style="[iconStyle]"></view>
|
||||
</slot>
|
||||
<text class="l-checkbox__label" :style="[labelStyle]" :class="labelClass" v-if="label || $slots['default']">
|
||||
<slot>{{label}}</slot>
|
||||
</text>
|
||||
</slot>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* Checkbox 复选框组件
|
||||
* @description 用于在多个选项中进行选择的表单组件,支持单选、全选和不确定态
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-checkbox
|
||||
*
|
||||
* @property {boolean} defaultChecked 默认选中状态(非受控属性)
|
||||
* @property {string} label 显示文本(支持插槽)
|
||||
* @property {boolean} indeterminate 半选状态(优先级高于checked)
|
||||
* @property {boolean} disabled 禁用状态(覆盖Group设置)
|
||||
* @property {'small' | 'medium' | 'large'} size 组件尺寸
|
||||
* @value small
|
||||
* @value medium
|
||||
* @value large
|
||||
* @property {string} name 唯一标识符(表单提交使用)
|
||||
* @property {boolean} checkAll 标记为全选选项(需在Group中使用)
|
||||
* @property {string} value 选项值(Group模式下必填)
|
||||
* @property {'circle' | 'line' | 'rectangle' | 'dot'} icon 图标样式类型
|
||||
* @value circle 圆
|
||||
* @value line 线
|
||||
* @value rectangle 方
|
||||
* @value dot 点
|
||||
* @property {string} fontSize 文本字号(支持CSS单位)
|
||||
* @property {string} iconSize 图标尺寸(支持CSS单位)
|
||||
* @property {string} checkedColor 选中状态主题色
|
||||
* @property {string} iconBgColor 图标背景色
|
||||
* @property {string} iconBorderColor 图标边框色
|
||||
* @property {string} iconDisabledColor 禁用状态图标颜色
|
||||
* @property {string} iconDisabledBgColor 禁用状态背景色
|
||||
* @property {string|object} labelStyle label的样式
|
||||
* @event {Function} change 状态变化时触发(参数:CheckboxChangeOptions)
|
||||
*/
|
||||
import { type ManageChildInList, type CheckboxStatus, type OnCheckedChange, type CheckboxChangeOptions, type ComputedRef } from './type';
|
||||
import { computed, defineComponent, ref, inject, getCurrentInstance, onBeforeUnmount } from '@/uni_modules/lime-shared/vue'
|
||||
import checkboxProps from './props'
|
||||
const name = 'l-checkbox';
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: checkboxProps,
|
||||
emits: ['update:modelValue', 'input', 'change'],
|
||||
setup(props, { emit }) {
|
||||
const instance = getCurrentInstance()!
|
||||
const formDisabled = inject<Ref<boolean|null>|null>('formDisabled', null)
|
||||
const formReadonly = inject<Ref<boolean|null>|null>('formReadonly', null)
|
||||
const checkboxGroup = inject<LCheckboxGroupComponentPublicInstance|null>('limeCheckboxGroup', null);
|
||||
const checkboxGroupValue = inject<ComputedRef<any[]>|null>('limeCheckboxGroupValue', null);
|
||||
const checkboxGroupStatus = inject<ComputedRef<CheckboxStatus>|null>('limeCheckboxGroupStatus', null);
|
||||
const checkboxGroupCheckedSet = inject<ComputedRef<Set<any>>|null>('limeCheckboxGroupCheckedSet', null);
|
||||
const manageChildInList = inject<ManageChildInList|null>('limeCheckboxGroupManageChildInList', null);
|
||||
const onCheckedChange = inject<OnCheckedChange|null>('limeCheckboxGroupOnCheckedChange', null);
|
||||
if(manageChildInList != null) {
|
||||
manageChildInList(instance.proxy as LCheckboxComponentPublicInstance, true)
|
||||
}
|
||||
|
||||
const max = computed(():number => checkboxGroup?.max ?? -1)
|
||||
|
||||
const _innerChecked = ref(props.checked || props.modelValue || props.value || props.defaultChecked)
|
||||
const innerChecked = computed({
|
||||
set(value: boolean) {
|
||||
_innerChecked.value = value
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value)
|
||||
// #ifdef VUE2
|
||||
emit('input', value)
|
||||
// #endif
|
||||
},
|
||||
get():boolean {
|
||||
const value = (props.checked ?? props.modelValue ?? props.value)
|
||||
if(value != null) return value
|
||||
return _innerChecked.value
|
||||
|
||||
// return props.checked || props.modelValue || props.value || _innerChecked.value
|
||||
}
|
||||
} as WritableComputedOptions<boolean>)
|
||||
|
||||
const isChecked = computed(():boolean=>{
|
||||
if (props.checkAll) {
|
||||
const checkAllStatus = checkboxGroupStatus?.value || 'uncheck';
|
||||
return checkAllStatus == 'checked' || checkAllStatus == 'indeterminate'
|
||||
}
|
||||
const value = props.value || props.name;
|
||||
if (checkboxGroupCheckedSet && value) {
|
||||
return checkboxGroupCheckedSet.value.has(value)
|
||||
}
|
||||
return innerChecked.value;
|
||||
})
|
||||
|
||||
const isDisabled = computed(():boolean=>{
|
||||
if(max.value > -1 && checkboxGroupValue) {
|
||||
return max.value <= checkboxGroupValue.value.length && !isChecked.value;
|
||||
}
|
||||
if (props.disabled) return props.disabled;
|
||||
// return checkboxGroup?.disabled || false;
|
||||
return formDisabled?.value || checkboxGroup?.disabled || false;
|
||||
})
|
||||
|
||||
const isReadonly= computed(():boolean=>{
|
||||
if (props.readonly) return props.readonly;
|
||||
return formReadonly?.value ?? checkboxGroup?.readonly ?? false;
|
||||
})
|
||||
|
||||
const isIndeterminate = computed(():boolean=>{
|
||||
if (props.checkAll && checkboxGroupStatus) return checkboxGroupStatus.value == 'indeterminate';
|
||||
return props.indeterminate;
|
||||
})
|
||||
|
||||
const innerIcon = computed(():string => checkboxGroup?.icon || props.icon)
|
||||
const innerSize = computed(():string => checkboxGroup?.size || props.size)
|
||||
const innerIconSize = computed(():string|null => checkboxGroup?.iconSize || props.iconSize)
|
||||
const innerFontSize = computed(():string|null => checkboxGroup?.fontSize || props.fontSize)
|
||||
const innerCheckedColor = computed(():string|null => checkboxGroup?.checkedColor || props.checkedColor)
|
||||
const innerIconBgColor = computed(():string => props.iconBgColor || checkboxGroup?.iconBgColor)
|
||||
const innerIconBorderColor = computed(():string => props.iconBorderColor || checkboxGroup?.iconBorderColor)
|
||||
const innerIconDisabledColor = computed(():string => props.iconDisabledColor || checkboxGroup?.iconDisabledColor)
|
||||
const innerIconDisabledBgColor = computed(():string => props.iconDisabledBgColor || checkboxGroup?.iconDisabledBgColor)
|
||||
|
||||
|
||||
const rootCasses = computed(()=>{
|
||||
const cls = [`${name}--${props.size}`]
|
||||
if(isDisabled.value) {
|
||||
cls.push(`${name}--disabled`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
})
|
||||
|
||||
const iconClasses = computed(()=>{
|
||||
const cls = [`${name}__icon--${props.icon}`]
|
||||
if(isChecked.value) {
|
||||
cls.push(`${name}__icon--checked`)
|
||||
}
|
||||
if(isDisabled.value) {
|
||||
cls.push(`${name}__icon--disabled`)
|
||||
}
|
||||
if(isIndeterminate.value) {
|
||||
cls.push(`${name}__icon--indeterminate`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
})
|
||||
|
||||
const labelClass = computed(()=>{
|
||||
const cls = [];
|
||||
if(isDisabled.value) {
|
||||
cls.push(`${name}__label--disabled`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
})
|
||||
|
||||
const styles = computed(()=>{
|
||||
const style:Record<string, any> = {};
|
||||
if(checkboxGroup && checkboxGroup.gap) {
|
||||
style[checkboxGroup.direction == 'horizontal' ? 'margin-right' : 'margin-bottom'] = checkboxGroup.gap!
|
||||
}
|
||||
if(innerCheckedColor.value) {
|
||||
style['--l-checkbox-icon-checked-color'] = innerCheckedColor.value!
|
||||
}
|
||||
if(innerIconBorderColor.value) {
|
||||
style['--l-checkbox-icon-border-color'] = innerIconBorderColor.value!
|
||||
}
|
||||
if(innerIconDisabledColor.value) {
|
||||
style['--l-checkbox-icon-disabled-color'] = innerIconDisabledColor.value!
|
||||
}
|
||||
if(innerIconDisabledBgColor.value) {
|
||||
style['--l-checkbox-icon-disabled-bg-color'] = innerIconDisabledBgColor.value!
|
||||
}
|
||||
if(innerFontSize.value) {
|
||||
style['--l-checkbox-font-size'] = innerFontSize.value!
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
const iconStyle = computed(()=>{
|
||||
const style:Record<string, any> = {}
|
||||
if(innerIconSize.value) {
|
||||
style['width'] = innerIconSize.value!
|
||||
style['height'] = innerIconSize.value!
|
||||
style['--l-checkbox-icon-size'] = innerIconSize.value!
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
// const labelStyle = computed(()=>{
|
||||
// const style:Record<string, any> = {}
|
||||
// const fontSize = props.fontSize || checkboxGroup?.fontSize
|
||||
// if(fontSize) {
|
||||
// style['font-size'] = fontSize
|
||||
// }
|
||||
// return style
|
||||
// })
|
||||
|
||||
const handleChange = (e: UniPointerEvent) => {
|
||||
if (isDisabled.value || isReadonly.value) return;
|
||||
const value = !isChecked.value;
|
||||
innerChecked.value = value;
|
||||
|
||||
if(onCheckedChange) {
|
||||
onCheckedChange({
|
||||
checked: value,
|
||||
checkAll: props.checkAll,
|
||||
value: props.value || props.name //?? instance.uid
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(()=>{
|
||||
if(manageChildInList) {
|
||||
manageChildInList(instance.proxy as LCheckboxComponentPublicInstance, false)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
return {
|
||||
isChecked,
|
||||
isDisabled,
|
||||
rootCasses,
|
||||
iconClasses,
|
||||
labelClass,
|
||||
styles,
|
||||
iconStyle,
|
||||
// labelStyle,
|
||||
handleChange
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index-u';
|
||||
</style>
|
||||
@@ -0,0 +1,87 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
/** 是否选中,非受控属性 */
|
||||
defaultChecked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 是否禁用组件。如果父组件存在 CheckboxGroup,默认值由 CheckboxGroup.disabled 控制。Checkbox.disabled 优先级高于 CheckboxGroup.disabled */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 主文案 */
|
||||
label: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
/** 用于标识是否为「全选选项」。单独使用无效,需在 CheckboxGroup 中使用 */
|
||||
checkAll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 多选框的值 */
|
||||
value: {
|
||||
type: [String, Number, Boolean],
|
||||
default: null
|
||||
},
|
||||
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
|
||||
},
|
||||
labelStyle: {
|
||||
type: [String, Object]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// @ts-nocheck
|
||||
export type CheckboxProps = {
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
// checked ?: boolean;
|
||||
/**
|
||||
* 是否选中,非受控属性
|
||||
*/
|
||||
defaultChecked: boolean;
|
||||
/**
|
||||
* 是否选中
|
||||
*/
|
||||
// modelValue ?: boolean;
|
||||
/**
|
||||
* 主文案
|
||||
*/
|
||||
label ?: string;
|
||||
/**
|
||||
* 是否为半选
|
||||
*/
|
||||
indeterminate: boolean;
|
||||
/**
|
||||
* 是否禁用组件。如果父组件存在 CheckboxGroup,默认值由 CheckboxGroup.disabled 控制。Checkbox.disabled 优先级高于 CheckboxGroup.disabled
|
||||
*/
|
||||
disabled : boolean;
|
||||
/**
|
||||
* 只读
|
||||
*/
|
||||
readonly : boolean;
|
||||
size : 'small' | 'medium' | 'large'
|
||||
/**
|
||||
* 标识符,通常为一个唯一的字符串或数字
|
||||
*/
|
||||
name ?: any //string,
|
||||
/**
|
||||
* 用于标识是否为「全选选项」。单独使用无效,需在 CheckboxGroup 中使用
|
||||
*/
|
||||
checkAll : boolean
|
||||
/**
|
||||
* 多选框的值
|
||||
*/
|
||||
value?: any; // string | number
|
||||
icon: 'circle' | 'line' | 'rectangle' | 'dot';
|
||||
|
||||
fontSize?: string;
|
||||
iconSize?: string;
|
||||
checkedColor?: string;
|
||||
iconBgColor?: string;
|
||||
iconBorderColor?: string;
|
||||
iconDisabledColor?: string;
|
||||
iconDisabledBgColor?: string;
|
||||
|
||||
labelStyle?: string | UTSJSONObject
|
||||
}
|
||||
|
||||
export type ManageChildInList = (child: LCheckboxComponentPublicInstance, shouldAdd: boolean) => void;
|
||||
export type CheckboxStatus = 'checked' | 'uncheck' | 'indeterminate';
|
||||
export type CheckboxChangeOptions = {
|
||||
checked : boolean,
|
||||
checkAll : boolean,
|
||||
value?: any
|
||||
};
|
||||
|
||||
export type OnCheckedChange = (options: CheckboxChangeOptions) => void
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
export type {ComputedRef} from 'vue';
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
export type ComputedRef<T> = ComputedRefImpl<T>;
|
||||
// export type WritableComputedRef<T> = ComputedRefImpl<T>;
|
||||
// #endif
|
||||
109
qiming-mobile/uni_modules/lime-checkbox/package.json
Normal file
109
qiming-mobile/uni_modules/lime-checkbox/package.json
Normal file
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"id": "lime-checkbox",
|
||||
"displayName": "lime-checkbox 复选框",
|
||||
"version": "0.1.0",
|
||||
"description": "lime-checkbox 复选框,支持v-model双向数据绑定,支持自定义样式,支持半选,兼容uniapp/uniappx",
|
||||
"keywords": [
|
||||
"lime-checkbox",
|
||||
"checkbox",
|
||||
"复选框",
|
||||
"半选"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^4.34",
|
||||
"uni-app": "^4.73",
|
||||
"uni-app-x": "^4.75"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"darkmode": "√",
|
||||
"i18n": "x",
|
||||
"widescreen": "x"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared",
|
||||
"lime-style"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "√",
|
||||
"aliyun": "√",
|
||||
"alipay": "√"
|
||||
},
|
||||
"client": {
|
||||
"uni-app": {
|
||||
"vue": {
|
||||
"vue2": "√",
|
||||
"vue3": "√"
|
||||
},
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"vue": "√",
|
||||
"nvue": "-",
|
||||
"android": {
|
||||
"extVersion": "",
|
||||
"minVersion": "21"
|
||||
},
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√",
|
||||
"alipay": "-",
|
||||
"toutiao": "-",
|
||||
"baidu": "-",
|
||||
"kuaishou": "-",
|
||||
"jd": "-",
|
||||
"harmony": "-",
|
||||
"qq": "-",
|
||||
"lark": "-"
|
||||
},
|
||||
"quickapp": {
|
||||
"huawei": "-",
|
||||
"union": "-"
|
||||
}
|
||||
},
|
||||
"uni-app-x": {
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"android": {
|
||||
"extVersion": "",
|
||||
"minVersion": "21"
|
||||
},
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
258
qiming-mobile/uni_modules/lime-checkbox/readme_old.md
Normal file
258
qiming-mobile/uni_modules/lime-checkbox/readme_old.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# lime-checkbox 复选框
|
||||
复选框,支持v-model双向数据绑定,支持自定义样式,兼容uniapp/uniappx
|
||||
|
||||
## 文档
|
||||
🚀 [checkbox【站点1】](https://limex.qcoon.cn/components/checkbox.html)
|
||||
🌍 [checkbox【站点2】](https://limeui.netlify.app/components/checkbox.html)
|
||||
🔥 [checkbox【站点3】](https://limeui.familyzone.top/components/checkbox.html)
|
||||
|
||||
|
||||
|
||||
## 安装
|
||||
插件市场导入即可,首次导入可能需要重新编译
|
||||
|
||||
## 代码演示
|
||||
### 基础演示
|
||||
通过 `v-model` 绑定复选框的勾选状态。
|
||||
```html
|
||||
<l-checkbox v-model="checked">复选框</l-checkbox>
|
||||
```
|
||||
```js
|
||||
const checked = ref(false)
|
||||
```
|
||||
|
||||
|
||||
### 选项组
|
||||
通过 v-model 绑定值当前选中项的 `value`或`name`。
|
||||
```html
|
||||
<l-checkbox-group v-model="checked" @change="onChange">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Shanghai" label="上海" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
```js
|
||||
const checked = ref(['Beijing']);
|
||||
|
||||
const onChange = (e: string[]) => {
|
||||
console.log('onChange', e)
|
||||
}
|
||||
```
|
||||
|
||||
### 禁用
|
||||
通过 `disabled` 属性禁止选项切换,在 checkbox 上设置 `disabled` 可以禁用单个选项。
|
||||
```html
|
||||
<l-checkbox-group v-model="checked" disabled>
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Shanghai" label="上海" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
### 样式
|
||||
`icon` 属性可选值为`circle`(圆) `line`(线) `dot`(点),复选框形状。
|
||||
```html
|
||||
<l-checkbox-group icon="dot">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
<l-checkbox-group icon="circle">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
<l-checkbox-group icon="line">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
### 自定义颜色
|
||||
通过 `checked-color` 属性设置选中状态的图标颜色。
|
||||
```html
|
||||
<l-checkbox-group checked-color="#ee0a24">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
### 自定义大小
|
||||
通过 `icon-size` 属性可以自定义图标的大小。
|
||||
```html
|
||||
<l-checkbox-group>
|
||||
<l-checkbox icon-size="44px" value="Beijing" label="北京" />
|
||||
<l-checkbox icon-size="34px" value="Guangzhou" label="广州" />
|
||||
<l-checkbox icon-size="24px" value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
### 自定义图标
|
||||
|
||||
通过 `icon` 插槽自定义图标,并通过 `slotProps` 判断是否为选中状态。
|
||||
```html
|
||||
<l-checkbox-group>
|
||||
<l-checkbox value="Beijing" label="北京">
|
||||
<template #icon="{checked}">
|
||||
<image v-show="checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-active.png"></image>
|
||||
<image v-show="!checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-inactive.png"></image>
|
||||
</template>
|
||||
</l-checkbox>
|
||||
<l-checkbox value="Guangzhou" label="广州">
|
||||
<template #icon="{checked}">
|
||||
<image v-show="checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-active.png"></image>
|
||||
<image v-show="!checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-inactive.png"></image>
|
||||
</template>
|
||||
</l-checkbox>
|
||||
<l-checkbox value="Shenzen" label="深圳">
|
||||
<template #icon="{checked}">
|
||||
<image v-show="checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-active.png"></image>
|
||||
<image v-show="!checked" style="width:20px; height:20px" src="https://fastly.jsdelivr.net/npm/@vant/assets/user-inactive.png"></image>
|
||||
</template>
|
||||
</l-checkbox>
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
|
||||
### 限制最大可选数
|
||||
通过 `max` 属性可以限制复选框组的最大可选数。
|
||||
```html
|
||||
<l-checkbox-group :max="3">
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Shanghai" label="上海" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
```
|
||||
|
||||
### 全选与反选
|
||||
通过 `CheckboxGroup` 实例上的 `toggleAll` 方法可以实现全选与反选。
|
||||
```html
|
||||
<l-checkbox-group ref="checkboxGroupRef" @change="onChange" direction="vertical">
|
||||
<l-checkbox value="all" checkAll label="全选" />
|
||||
<l-checkbox value="Beijing" label="北京" />
|
||||
<l-checkbox value="Shanghai" label="上海" />
|
||||
<l-checkbox value="Guangzhou" label="广州" />
|
||||
<l-checkbox value="Shenzen" label="深圳" />
|
||||
</l-checkbox-group>
|
||||
<button type="primary" @click="checkAll">全选</button>
|
||||
<button @click="toggleAll">反选</button>
|
||||
```
|
||||
```js
|
||||
const checkboxGroupRef = ref<LCheckboxGroupComponentPublicInstance|null>(null);
|
||||
const onChange = (e: string[]) => {
|
||||
console.log('onChange', e)
|
||||
}
|
||||
const checkAll = () => {
|
||||
if(checkboxGroupRef.value == null) return
|
||||
checkboxGroupRef.value!.toggleAll(true)
|
||||
}
|
||||
const toggleAll = () => {
|
||||
if(checkboxGroupRef.value == null) return
|
||||
checkboxGroupRef.value!.toggleAll(false)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 插件标签
|
||||
`l-checkbox` 为 component
|
||||
`lime-checkbox` 为 demo
|
||||
|
||||
### Vue2使用
|
||||
插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||
关键代码是: 在main.js中 在vue2部分加上这一段即可
|
||||
|
||||
```js
|
||||
// vue2
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Checkbox Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| name | 标识符,通常为一个唯一的字符串或数字 | _string\|number_ | - |
|
||||
| value | 复选按钮的值 | _any_ | - |
|
||||
| v-model | 是否选中 | _any_ | - |
|
||||
| indeterminate | 是否为半选 | _boolean_ | `false` |
|
||||
| checked | 是否选中 | _boolean_ | `false` |
|
||||
| disabled | 是否为禁用态 | _boolean_ | `false` |
|
||||
| readonly | 是否为只读 | _boolean_ | `false` |
|
||||
| checkAll | 用于标识是否为「全选选项」。复独使用无效 | _boolean_ | `false` |
|
||||
| icon | 自定义选中图标和非选中图标可选值`'rectangle' | 'circle' | 'line' | 'dot'` | _string_ | `rectangle` |
|
||||
| label | 主文案 | _string_ | `` |
|
||||
| fontSize | 文本大小 | _string_ | `` |
|
||||
| iconSize | 图标大小 | _string_ | `` |
|
||||
| checkedColor | 选中状态颜色 | _string_ | `` |
|
||||
| iconBgColor | 图标背景颜色 | _string_ | `` |
|
||||
| iconBorderColor | 图标描边颜色 | _string_ | `` |
|
||||
| iconDisabledColor | 图标禁用颜色 | _string_ | `` |
|
||||
| iconDisabledBgColor | 图标禁用背景颜色 | _string_ | `` |
|
||||
| labelStyle | label的样式 | _string\|object | `` |
|
||||
|
||||
### CheckboxGroup Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model | 标识符,通常为一个唯一的字符串或数字 | _string\|number[]_ | - |
|
||||
| name | 标识符,通常为一个唯一的字符串或数字 | _string\|number_ | - |
|
||||
| value | 复选按钮的值 | _any[]_ | - |
|
||||
| indeterminate | 是否为半选 | _boolean_ | `false` |
|
||||
| disabled | 是否为禁用态 | _boolean_ | `false` |
|
||||
| direction | 排列方向,可选值为`vertical` | _string_ | `horizontal` |
|
||||
| icon | 自定义选中图标和非选中图标可选值`'rectangle' | 'circle' | 'line' | 'dot'` | _string_ | `rectangle` |
|
||||
| fontSize | 文本大小 | _string_ | `` |
|
||||
| iconSize | 图标大小 | _string_ | `` |
|
||||
| checkedColor | 选中状态颜色 | _string_ | `` |
|
||||
| iconBgColor | 图标背景颜色 | _string_ | `` |
|
||||
| iconBorderColor | 图标描边颜色 | _string_ | `` |
|
||||
| iconDisabledColor | 图标禁用颜色 | _string_ | `` |
|
||||
| iconDisabledBgColor | 图标禁用背景颜色 | _string_ | `` |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| ------ | ------------------------ | ---------------------- |
|
||||
| change | 当绑定值变化时触发的事件 | _currentValue: any_ |
|
||||
|
||||
|
||||
### Radio Slots
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| ------ | ------------------------ | ---------------------- |
|
||||
| default | 自定义文本 | _{ checked: boolean, disabled: boolean }_ |
|
||||
| icon | 自定义图标 | _{ checked: boolean, disabled: boolean }_ |
|
||||
|
||||
|
||||
## 主题定制
|
||||
|
||||
### 样式变量
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式,uvue app无效。
|
||||
|
||||
| 名称 | 默认值 | 描述 |
|
||||
| ------------------------ | -------------------- | ---- |
|
||||
| --l-checkbox-icon-size | _40rpx_ | - |
|
||||
| --l-checkbox-font-size | _32rpx_ | - |
|
||||
| --l-checkbox-icon-bg-color | _white_ | - |
|
||||
| --l-checkbox-border-icon-color | _$gray-5_ | - |
|
||||
| --l-checkbox-icon-disabled-color | _$gray-5_ | - |
|
||||
| --l-checkbox-icon-disabled-bg-color | _$gray-1_ | - |
|
||||
| --l-checkbox-icon-checked-color | _$primary-color_ | - |
|
||||
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
||||
Reference in New Issue
Block a user