CNCEC_APP/uni_modules/uview-pro/components/u-checkbox/u-checkbox.vue

306 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="u-checkbox" :style="$u.toStyle(checkboxStyle, customStyle)" :class="customClass">
<view class="u-checkbox__icon-wrap" @tap="toggle" :class="iconClass" :style="$u.toStyle(iconStyle)">
<u-icon
class="u-checkbox__icon-wrap__icon"
name="checkbox-mark"
:size="checkboxIconSize"
:color="iconColor"
/>
</view>
<view
class="u-checkbox__label"
@tap="onClickLabel"
:style="{
fontSize: $u.addUnit(labelSize)
}"
>
<slot>
{{ label }}
</slot>
</view>
</view>
</template>
<script lang="ts">
export default {
name: 'u-checkbox',
options: {
addGlobalClass: true,
// #ifndef MP-TOUTIAO
virtualHost: true,
// #endif
styleIsolation: 'shared'
}
};
</script>
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { $u, useChildren } from '../..';
import { CheckboxProps } from './types';
/**
* checkbox 复选框
* @description 该组件需要搭配checkboxGroup组件使用以便用户进行操作时获得当前复选框组的选中情况。
* @tutorial https://uviewpro.cn/zh/components/checkbox.html
* @property {String Number} icon-size 图标大小单位rpx默认20
* @property {String Number} label-size label字体大小单位rpx默认28
* @property {String Number} name checkbox组件的标示符
* @property {String} shape 形状见官网说明默认circle
* @property {Boolean} disabled 是否禁用
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox
* @property {String} active-color 选中时的颜色如设置CheckboxGroup的active-color将失效
* @event {Function} change 某个checkbox状态发生变化时触发回调为一个对象
* @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
*/
const props = defineProps(CheckboxProps);
const emit = defineEmits(['change', 'update:modelValue']);
// checkbox 是否选中true/false
const checkedValue = ref(props.modelValue);
// checkbox 的value值id
const checkboxValue = computed(() => {
if (props.value !== '') return props.value;
return props.name;
});
watch(
() => props.modelValue,
(newVal: boolean) => {
checkedValue.value = newVal;
}
);
watch(
() => checkedValue.value,
(newVal: boolean) => {
emit('update:modelValue', newVal);
},
{ immediate: true }
);
// 使用子组件Hook
const { parentExposed } = useChildren('u-checkbox', 'u-checkbox-group');
// 是否禁用如果父组件u-checkbox-group禁用的话将会忽略子组件的配置
const isDisabled = computed(() => {
return props.disabled !== '' ? props.disabled : (parentExposed.value?.props?.disabled ?? false);
});
// 是否禁用label点击
const isLabelDisabled = computed(() => {
return props.labelDisabled !== '' ? props.labelDisabled : (parentExposed.value?.props?.labelDisabled ?? false);
});
// 组件尺寸对应size的值默认值为34rpx
const checkboxSize = computed(() => {
return props.size ? props.size : (parentExposed.value?.props?.size ?? 34);
});
// 组件的勾选图标的尺寸默认20
const checkboxIconSize = computed(() => {
return props.iconSize ? props.iconSize : (parentExposed.value?.props?.iconSize ?? 20);
});
// 组件选中激活时的颜色
const elActiveColor = computed(() => {
return props.activeColor ? props.activeColor : (parentExposed.value?.props?.activeColor ?? 'primary');
});
// 组件的形状
const elShape = computed(() => {
return props.shape ? props.shape : (parentExposed.value?.props?.shape ?? 'square');
});
// 图标样式
const iconStyle = computed(() => {
let style: Record<string, string> = {};
if (elActiveColor.value && checkedValue.value && !isDisabled.value) {
style.borderColor = elActiveColor.value;
style.backgroundColor = elActiveColor.value;
}
style.width = $u.addUnit(checkboxSize.value);
style.height = $u.addUnit(checkboxSize.value);
return style;
});
// checkbox内部的勾选图标如果选中状态为白色否则为透明色即可
const iconColor = computed(() => {
return checkedValue.value ? 'var(--u-white-color)' : 'transparent';
});
const iconClass = computed(() => {
let classes: string[] = [];
classes.push('u-checkbox__icon-wrap--' + elShape.value);
if (checkedValue.value == true) classes.push('u-checkbox__icon-wrap--checked');
if (isDisabled.value) classes.push('u-checkbox__icon-wrap--disabled');
if (checkedValue.value && isDisabled.value) classes.push('u-checkbox__icon-wrap--disabled--checked');
return classes.join(' ');
});
const checkboxStyle = computed(() => {
let style: Record<string, string> = {};
if (parentExposed.value?.props?.width) {
style.width = parentExposed.value.props.width;
// #ifdef MP
style.float = 'left';
// #endif
// #ifndef MP
style.flex = `0 0 ${parentExposed.value.props.width}`;
// #endif
}
if (parentExposed.value?.props?.wrap) {
style.width = '100%';
// #ifndef MP
style.flex = '0 0 100%';
// #endif
}
return style;
});
/**
* 点击label
*/
function onClickLabel() {
if (!isLabelDisabled.value && !isDisabled.value) {
setValue();
}
}
/**
* 点击icon
*/
function toggle() {
if (!isDisabled.value) {
setValue();
}
}
/**
* 触发change事件
*/
function emitEvent() {
emit('change', !checkedValue.value);
// 通知父组件状态变化
setTimeout(() => {
if (parentExposed.value?.emitEvent) {
parentExposed.value.emitEvent();
}
}, 80);
}
/**
* 设置通过v-model绑定的组件的值
*/
function setValue() {
// 判断是否超过了可选的最大数量
if (checkedValue.value == true) {
emitEvent();
checkedValue.value = false;
} else {
if (parentExposed?.value?.validateSelection && !parentExposed?.value?.validateSelection()) {
return;
}
emitEvent();
checkedValue.value = true;
}
}
// 设置组件的modelValue值
function setChecked(data: any) {
if (!isDisabled.value) {
const needEmit = checkedValue.value !== data.checked;
checkedValue.value = data.checked;
if (needEmit) {
emitEvent();
}
}
}
defineExpose({
isChecked: computed(() => checkedValue.value),
label: props.label,
name: props.name,
value: checkboxValue.value,
setValue,
emitEvent,
props,
setChecked
});
</script>
<style lang="scss" scoped>
@import '../../libs/css/style.components.scss';
.u-checkbox {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
align-items: center;
overflow: hidden;
user-select: none;
line-height: 1.8;
&__icon-wrap {
color: $u-content-color;
flex: none;
display: -webkit-flex;
@include vue-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 42rpx;
height: 42rpx;
color: transparent;
text-align: center;
transition-property: color, border-color, background-color;
font-size: 20px;
border: 1px solid var(--u-border-color);
transition-duration: 0.2s;
/* #ifdef MP-TOUTIAO */
&__icon {
line-height: 0;
}
/* #endif */
&--circle {
border-radius: 100%;
}
&--square {
border-radius: 6rpx;
}
&--checked {
color: var(--u-white-color);
background-color: $u-type-primary;
border-color: $u-type-primary;
}
&--disabled {
background-color: var(--u-bg-gray-light);
border-color: var(--u-border-color);
}
&--disabled--checked {
color: var(--u-bg-gray-light) !important;
}
}
&__label {
word-wrap: break-word;
margin-left: 10rpx;
margin-right: 24rpx;
color: $u-content-color;
font-size: 30rpx;
&--disabled {
color: var(--u-bg-gray-light);
}
}
}
</style>