chore: initialize qiming workspace repository
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user