init
This commit is contained in:
65
uni_modules/nutui-uni/components/checkbox/checkbox.ts
Normal file
65
uni_modules/nutui-uni/components/checkbox/checkbox.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../_constants'
|
||||
import { commonProps, makeNumericProp, makeStringProp, nullableBooleanProp } from '../_utils'
|
||||
|
||||
export const checkboxProps = {
|
||||
...commonProps,
|
||||
/**
|
||||
* @description 是否处于选中状态
|
||||
*/
|
||||
modelValue: {
|
||||
type: [Boolean, Number, String],
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* @description 是否禁用选择
|
||||
*/
|
||||
disabled: nullableBooleanProp,
|
||||
/**
|
||||
* @description 文本所在的位置,可选值:`left`,`right`
|
||||
*/
|
||||
textPosition: makeStringProp<'left' | 'right'>('right'),
|
||||
/**
|
||||
* @description 图标大小,如 20px 2em 2rem
|
||||
*/
|
||||
iconSize: makeNumericProp(''),
|
||||
/**
|
||||
* @description 复选框标识
|
||||
*/
|
||||
label: [Boolean, Number, String],
|
||||
/**
|
||||
* @description 当前是否支持半选状态,一般用在全选操作中
|
||||
*/
|
||||
indeterminate: Boolean,
|
||||
/**
|
||||
* @description 形状,可选值:`button`、`round`
|
||||
*/
|
||||
shape: makeStringProp<'button' | 'round'>('round'),
|
||||
/**
|
||||
* @description 选中状态的值
|
||||
*/
|
||||
checkedValue: {
|
||||
type: [Boolean, Number, String],
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* @description 未选中状态的值
|
||||
*/
|
||||
uncheckedValue: {
|
||||
type: [Boolean, Number, String],
|
||||
default: false,
|
||||
},
|
||||
}
|
||||
|
||||
export type CheckboxProps = ExtractPropTypes<typeof checkboxProps>
|
||||
|
||||
/* eslint-disable unused-imports/no-unused-vars */
|
||||
export const checkboxEmits = {
|
||||
[UPDATE_MODEL_EVENT]: (value: any) => true,
|
||||
[CHANGE_EVENT]: (checked: boolean, value: any) => true,
|
||||
}
|
||||
/* eslint-enable unused-imports/no-unused-vars */
|
||||
|
||||
export type CheckboxEmits = typeof checkboxEmits
|
||||
|
||||
export const CHECKBOX_KEY = Symbol('nut-checkbox')
|
||||
208
uni_modules/nutui-uni/components/checkbox/checkbox.vue
Normal file
208
uni_modules/nutui-uni/components/checkbox/checkbox.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ComputedRef } from 'vue'
|
||||
import { computed, defineComponent, reactive, toRef, useSlots, watch } from 'vue'
|
||||
import { CHANGE_EVENT, PREFIX, UPDATE_MODEL_EVENT } from '../_constants'
|
||||
import { useInject } from '../_hooks'
|
||||
import { getMainClass, pxCheck } from '../_utils'
|
||||
import { useFormDisabled } from '../form/form'
|
||||
import NutIcon from '../icon/icon.vue'
|
||||
import { CHECKBOX_KEY, checkboxEmits, checkboxProps } from './checkbox'
|
||||
|
||||
const props = defineProps(checkboxProps)
|
||||
|
||||
const emit = defineEmits(checkboxEmits)
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const disabled = useFormDisabled(toRef(props, 'disabled'))
|
||||
|
||||
const { parent } = useInject<{
|
||||
value: ComputedRef<any[]>
|
||||
disabled: ComputedRef<boolean | undefined>
|
||||
max: ComputedRef<number>
|
||||
updateValue: (value: any[]) => void
|
||||
}>(CHECKBOX_KEY)
|
||||
|
||||
const state = reactive({
|
||||
partialSelect: props.indeterminate,
|
||||
})
|
||||
|
||||
function isCheckedValue<T>(value: T) {
|
||||
return value === props.checkedValue
|
||||
}
|
||||
|
||||
const innerChecked = computed(() => {
|
||||
if (parent != null)
|
||||
return parent.value.value.includes(props.label)
|
||||
|
||||
return isCheckedValue(props.modelValue)
|
||||
})
|
||||
|
||||
const innerDisabled = computed(() => {
|
||||
if (parent != null && parent.disabled.value != null)
|
||||
return parent.disabled.value
|
||||
|
||||
return disabled.value
|
||||
})
|
||||
|
||||
const classes = computed(() => {
|
||||
return getMainClass(props, componentName, {
|
||||
[`${componentName}--reverse`]: props.textPosition === 'left',
|
||||
})
|
||||
})
|
||||
|
||||
const iconClasses = computed(() => {
|
||||
return {
|
||||
[`${componentName}__icon`]: true,
|
||||
[`${componentName}__icon--disabled`]: innerDisabled.value,
|
||||
// TODO 2.x移除
|
||||
[`${componentName}__icon--disable`]: innerDisabled.value,
|
||||
[`${componentName}__icon--indeterminate`]: state.partialSelect,
|
||||
[`${componentName}__icon--unchecked`]: !innerChecked.value,
|
||||
}
|
||||
})
|
||||
|
||||
const labelClasses = computed(() => {
|
||||
return {
|
||||
[`${componentName}__label`]: true,
|
||||
[`${componentName}__label--disabled`]: innerDisabled.value,
|
||||
}
|
||||
})
|
||||
|
||||
const buttonClasses = computed(() => {
|
||||
return {
|
||||
[`${componentName}__button`]: true,
|
||||
[`${componentName}__button--active`]: innerChecked.value,
|
||||
[`${componentName}__button--disabled`]: innerDisabled.value,
|
||||
}
|
||||
})
|
||||
|
||||
let updateSource: '' | 'click' = ''
|
||||
|
||||
function emitClickChange(checked: boolean, value: any) {
|
||||
updateSource = 'click'
|
||||
|
||||
emit(UPDATE_MODEL_EVENT, value)
|
||||
emit(CHANGE_EVENT, checked, value)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (value) => {
|
||||
if (updateSource === 'click') {
|
||||
updateSource = ''
|
||||
return
|
||||
}
|
||||
|
||||
if (parent == null)
|
||||
emit(CHANGE_EVENT, isCheckedValue(value), value)
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
if (innerDisabled.value)
|
||||
return
|
||||
|
||||
if (parent != null) {
|
||||
const values = parent.value.value
|
||||
const max = parent.max.value
|
||||
|
||||
const index = values.indexOf(props.label)
|
||||
|
||||
if (index >= 0) {
|
||||
values.splice(index, 1)
|
||||
|
||||
emitClickChange(false, props.label)
|
||||
}
|
||||
else {
|
||||
if (max <= 0 || values.length < max) {
|
||||
values.push(props.label)
|
||||
|
||||
emitClickChange(true, props.label)
|
||||
}
|
||||
}
|
||||
|
||||
parent.updateValue(values)
|
||||
}
|
||||
else {
|
||||
if (innerChecked.value && !state.partialSelect)
|
||||
emitClickChange(false, props.uncheckedValue)
|
||||
else
|
||||
emitClickChange(true, props.checkedValue)
|
||||
}
|
||||
|
||||
if (state.partialSelect)
|
||||
state.partialSelect = false
|
||||
}
|
||||
|
||||
watch(() => props.indeterminate, (value) => {
|
||||
state.partialSelect = value
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-checkbox`
|
||||
|
||||
export default defineComponent({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view :class="classes" :style="props.customStyle" @click="handleClick">
|
||||
<view v-if="props.shape === 'button'" :class="buttonClasses">
|
||||
<slot />
|
||||
</view>
|
||||
|
||||
<template v-else>
|
||||
<template v-if="state.partialSelect">
|
||||
<slot v-if="slots.indeterminate" name="indeterminate" />
|
||||
|
||||
<NutIcon
|
||||
v-else
|
||||
:custom-class="iconClasses"
|
||||
name="check-disabled"
|
||||
:size="pxCheck(props.iconSize)"
|
||||
:width="pxCheck(props.iconSize)"
|
||||
:height="pxCheck(props.iconSize)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else-if="!innerChecked">
|
||||
<slot v-if="slots.icon" name="icon" />
|
||||
|
||||
<NutIcon
|
||||
v-else
|
||||
:custom-class="iconClasses"
|
||||
name="check-normal"
|
||||
:size="pxCheck(props.iconSize)"
|
||||
:width="pxCheck(props.iconSize)"
|
||||
:height="pxCheck(props.iconSize)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<slot v-if="slots.checkedIcon" name="checkedIcon" />
|
||||
|
||||
<NutIcon
|
||||
v-else
|
||||
:custom-class="iconClasses"
|
||||
name="checked"
|
||||
:size="pxCheck(props.iconSize)"
|
||||
:width="pxCheck(props.iconSize)"
|
||||
:height="pxCheck(props.iconSize)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<view :class="labelClasses">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./index";
|
||||
</style>
|
||||
108
uni_modules/nutui-uni/components/checkbox/index.scss
Normal file
108
uni_modules/nutui-uni/components/checkbox/index.scss
Normal file
@@ -0,0 +1,108 @@
|
||||
.nut-theme-dark {
|
||||
.nut-checkbox {
|
||||
&__label {
|
||||
color: $dark-color;
|
||||
|
||||
&--disabled {
|
||||
color: $checkbox-label-disable-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
color: $dark-color;
|
||||
background: $dark-background;
|
||||
|
||||
&--disabled {
|
||||
color: $checkbox-label-disable-color;
|
||||
border: 1px solid $checkbox-label-disable-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nut-checkbox {
|
||||
display: $checkbox-display;
|
||||
align-items: center;
|
||||
margin-right: $checkbox-margin-right;
|
||||
vertical-align: bottom;
|
||||
|
||||
&--reverse {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.nut-checkbox__label {
|
||||
margin-right: $checkbox-label-margin-left;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: $checkbox-button-padding;
|
||||
overflow: hidden;
|
||||
font-size: $checkbox-button-font-size;
|
||||
color: $checkbox-label-color;
|
||||
background: $checkbox-button-background;
|
||||
border: 1px solid $checkbox-button-border-color;
|
||||
border-radius: $checkbox-button-border-radius;
|
||||
|
||||
&--active {
|
||||
position: relative;
|
||||
color: $checkbox-button-font-color-active;
|
||||
background: transparent;
|
||||
border: 1px solid $checkbox-button-border-color-active;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: "";
|
||||
background-color: $checkbox-button-background-active;
|
||||
opacity: 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
color: $checkbox-label-disable-color;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
flex: 1;
|
||||
margin-left: $checkbox-label-margin-left;
|
||||
font-size: $checkbox-label-font-size;
|
||||
color: $checkbox-label-color;
|
||||
|
||||
&--disabled {
|
||||
color: $checkbox-label-disable-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: $checkbox-icon-font-size;
|
||||
color: $primary-color;
|
||||
transition-duration: 0.3s;
|
||||
transition-property: color, border-color, background-color;
|
||||
}
|
||||
|
||||
&__icon--unchecked {
|
||||
font-size: $checkbox-icon-font-size;
|
||||
color: $checkbox-icon-disable-color;
|
||||
}
|
||||
|
||||
&__icon--indeterminate {
|
||||
font-size: $checkbox-icon-font-size;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
&__icon--disabled,
|
||||
// TODO 2.x移除
|
||||
&__icon--disable {
|
||||
font-size: $checkbox-icon-font-size;
|
||||
color: $checkbox-icon-disable-color2;
|
||||
}
|
||||
}
|
||||
1
uni_modules/nutui-uni/components/checkbox/index.ts
Normal file
1
uni_modules/nutui-uni/components/checkbox/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './checkbox'
|
||||
Reference in New Issue
Block a user