<template>
<text v-if="!hasDefaultSlot" class="uni-checkbox-view uni-checkbox-icon" :class="checkboxClasses" @click.stop="handleTap">
{{ isChecked ? fontUnicode : '' }}
</text>
<view v-else class="uni-checkbox" @click.stop="handleTap">
<text class="uni-checkbox-view uni-checkbox-icon" :class="checkboxClasses">{{ isChecked ? fontUnicode : '' }}</text>
<text v-if="isStringSlot">
<slot></slot>
</text>
<slot v-else></slot>
</view>
</template>
<script lang="uts" setup>
import { CHECKBOX_GROUP_KEY, FORM_KEY, LABEL_KEY, buildPointerEvent } from '../common.uts'
import { UniCheckboxElement } from './global.uts'
import { LabelContext, CheckboxGroupContext } from '../types.uts'
interface CheckboxProps {
/**
* 是否禁用
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
disabled?: boolean;
/**
* 当前是否选中,可用来设置默认选中
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
checked?: boolean;
/**
* 表单的控件名称,作为键值对的一部分与表单(form组件)一同提交
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
value?: string;
/**
* 复选框选中图标的类名
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
iconClass?: string.ClassString;
/**
* 复选框未选中的类名
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
checkboxClass?: string.ClassString;
/**
* 复选框选中的类名
* @uniPlatform {
"app": {
"harmony": {
"unixvVer": "5.0"
}
}
}
*/
checkboxActiveClass?: string.ClassString;
}
const props = withDefaults(defineProps<CheckboxProps>(), {
disabled: false,
checked: false,
value: '',
iconClass: '',
checkboxClass: '',
checkboxActiveClass: ''
})
defineOptions({
name: 'checkbox',
// @ts-ignore
rootElement: {
class: UniCheckboxElement
},
externalClasses: ['icon-class', 'checkbox-class', 'checkbox-active-class'],
})
const attrs = useAttrs()
const id = attrs.id
const slots = useSlots()
const isStringSlot = slots['default']?.['returnType'] === 'string'
const hasDefaultSlot = slots['default'] != null
const proxy = getCurrentInstance()?.proxy
const isChecked = ref(props.checked)
// TODO 需编译器修复
const fontUnicode = '\ueA08'
const group = inject<CheckboxGroupContext | null>(CHECKBOX_GROUP_KEY, null)
const labelCtx = inject<LabelContext | null>(LABEL_KEY, null)
const checkboxClasses = computed<string[]>(() => {
if (props.disabled) {
return ['uni-checkbox-disabled']
}
return [isChecked.value ? props.checkboxActiveClass : props.checkboxClass, props.iconClass]
})
watch(() => props.checked, (value : boolean) => {
if (isChecked.value === value) {
return
}
isChecked.value = value
if (group != null) {
group.toggle(props.value, value, false)
}
})
onMounted(() => {
// If inside a group, prefer group's current state
if (group != null) {
const current = group.isChecked(props.value)
// if group has no opinion yet, fall back to prop
const initial = current ? true : props.checked
isChecked.value = initial
group.register(props.value, isChecked.value, (checked: boolean) => {
if (isChecked.value !== checked) {
isChecked.value = checked
}
})
}
// Register with enclosing label if any
if (labelCtx != null) {
labelCtx.register({
id: id || props.value,
activate: (event: UniPointerEvent) => {
proxy?.$el?.dispatchEvent('click', buildPointerEvent(event))
},
getDisabled: () => props.disabled
})
}
})
onUnmounted(() => {
if (group != null) {
group.unregister(props.value)
}
if (labelCtx != null) {
labelCtx.unregister(id || props.value)
}
})
const handleTap = () => {
if (props.disabled) {
return
}
isChecked.value = !isChecked.value
if (group != null) {
group.toggle(props.value, isChecked.value, true)
}
}
</script>
<style>
.uni-checkbox {
flex-direction: row;
align-items: center;
}
.uni-checkbox-disabled {
background-color: #e1e1e1;
border-color: #d1d1d1;
color: #adadad;
}
.uni-checkbox-view {
width: 22px;
height: 22px;
border: 1px solid #d1d1d1;
background-color: #ffffff;
border-radius: 3px;
align-items: center;
justify-content: center;
margin-right: 5px;
/* #ifndef WEB */
text-align: center;
line-height: 22px;
/* #endif */
}
.uni-checkbox-icon {
font-size: 16px;
color: #007aff;
font-family: uni-icon;
}
</style>