mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 04:08:34 +08:00
refactor(checkbox): refactor checkbox component
This commit is contained in:
parent
a8d825bce8
commit
ab8c77f0ff
@ -51,12 +51,10 @@
|
||||
<script lang='ts'>
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
PropType,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { useCheckboxGroup } from './useCheckbox'
|
||||
import { useCheckbox, useCheckboxGroup } from './useCheckbox'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElCheckboxButton',
|
||||
@ -85,55 +83,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'change'],
|
||||
setup(props, { emit }) {
|
||||
let selfModel = false
|
||||
const { elForm, isGroup, checkboxGroup, elFormItemSize, elFormItem, ELEMENT } = useCheckboxGroup()
|
||||
const focus = ref(false)
|
||||
const isLimitExceeded = ref(false)
|
||||
const store = computed(() => checkboxGroup ? checkboxGroup.modelValue.value : props.modelValue)
|
||||
const model = computed({
|
||||
get() {
|
||||
return isGroup.value ? store.value : props.modelValue !== undefined ? props.modelValue : selfModel
|
||||
},
|
||||
|
||||
set(val: any) {
|
||||
if (isGroup.value) {
|
||||
isLimitExceeded.value = false
|
||||
|
||||
if (checkboxGroup.min !== undefined && val.length < checkboxGroup.min) {
|
||||
isLimitExceeded.value = true
|
||||
}
|
||||
if (checkboxGroup.max !== undefined && val.length > checkboxGroup.max) {
|
||||
isLimitExceeded.value = true
|
||||
}
|
||||
|
||||
isLimitExceeded.value === false && checkboxGroup.changeEvent?.(val)
|
||||
} else {
|
||||
emit('update:modelValue', val)
|
||||
selfModel = val
|
||||
}
|
||||
},
|
||||
})
|
||||
const isChecked = computed(() => {
|
||||
if (Object.prototype.toString.call(model.value) === '[object Boolean]') {
|
||||
return model.value
|
||||
} else if (Array.isArray(model.value)) {
|
||||
return model.value.includes(props.label)
|
||||
} else if (model.value !== null && model.value !== undefined) {
|
||||
return model.value === props.trueLabel
|
||||
}
|
||||
})
|
||||
const isLimitDisabled = computed(() => {
|
||||
const max = checkboxGroup.max
|
||||
const min = checkboxGroup.min
|
||||
return !!(max || min) && (model.value.length >= max && !isChecked.value) ||
|
||||
(model.value.length <= min && isChecked.value)
|
||||
})
|
||||
const isDisabled = computed(() => {
|
||||
return isGroup.value
|
||||
? checkboxGroup.disabled || props.disabled || (elForm as any || {} as any).disabled || isLimitDisabled.value
|
||||
: props.disabled || (elForm as any || {} as any).disabled
|
||||
})
|
||||
setup(props) {
|
||||
const { focus, isChecked, isDisabled, size, model, handleChange } = useCheckbox(props)
|
||||
const { checkboxGroup } = useCheckboxGroup()
|
||||
|
||||
const activeStyle = computed(() => {
|
||||
return {
|
||||
@ -144,37 +96,6 @@ export default defineComponent({
|
||||
}
|
||||
})
|
||||
|
||||
const size = computed(() => checkboxGroup.checkboxGroupSize || elFormItemSize || (ELEMENT || {}).size)
|
||||
|
||||
function addToStore() {
|
||||
if (
|
||||
Array.isArray(model.value) &&
|
||||
!model.value.includes(props.label)
|
||||
) {
|
||||
model.value.push(props.label)
|
||||
} else {
|
||||
model.value = props.trueLabel || true
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(e: UIEvent) {
|
||||
if (isLimitExceeded.value) return
|
||||
let value = ref(undefined)
|
||||
if ((e.target as HTMLInputElement).checked) {
|
||||
value.value = props.trueLabel === undefined ? true : props.trueLabel
|
||||
} else {
|
||||
value.value = props.falseLabel === undefined ? false : props.falseLabel
|
||||
}
|
||||
|
||||
emit('change', value.value, e)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, val => {
|
||||
elFormItem.changeEvent?.(val)
|
||||
})
|
||||
|
||||
props.checked && addToStore()
|
||||
|
||||
|
||||
return {
|
||||
focus,
|
||||
|
10
packages/checkbox/src/checkbox.d.ts
vendored
10
packages/checkbox/src/checkbox.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { ComputedRef, PropType } from 'vue'
|
||||
import { ComputedRef } from 'vue'
|
||||
export interface ICheckboxGroupInstance {
|
||||
name?: string
|
||||
modelValue?: ComputedRef
|
||||
@ -13,8 +13,8 @@ export interface ICheckboxGroupInstance {
|
||||
}
|
||||
|
||||
export interface ICheckboxProps {
|
||||
modelValue: ICheckboxModelValue
|
||||
label?:ICheckboxLabel
|
||||
modelValue: string | boolean | number
|
||||
label?:string | boolean | number
|
||||
indeterminate?: boolean
|
||||
disabled?: boolean
|
||||
checked?: boolean
|
||||
@ -27,6 +27,4 @@ export interface ICheckboxProps {
|
||||
size?: string
|
||||
}
|
||||
|
||||
export type ICheckboxLabel = PropType<string | boolean | number>
|
||||
export type ICheckboxModelValue = PropType<string | boolean | number>
|
||||
|
||||
export type IArgs<T extends (...args: any) => any> = Partial<ReturnType<T>>
|
||||
|
@ -60,14 +60,9 @@
|
||||
<script lang='ts'>
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
watch,
|
||||
onMounted,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
import { useCheckboxGroup } from './useCheckbox'
|
||||
import { useCheckbox, setAria } from './useCheckbox'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElCheckbox',
|
||||
@ -109,96 +104,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'change'],
|
||||
setup(props, { emit }) {
|
||||
let selfModel = false
|
||||
const { elForm, isGroup, checkboxGroup, elFormItemSize, elFormItem, ELEMENT } = useCheckboxGroup()
|
||||
const instance = getCurrentInstance()
|
||||
const focus = ref(false)
|
||||
const isLimitExceeded = ref(false)
|
||||
const store = computed(() => checkboxGroup ? checkboxGroup.modelValue.value : props.modelValue)
|
||||
const model = computed({
|
||||
get() {
|
||||
return isGroup.value
|
||||
? store.value : props.modelValue !== undefined ? props.modelValue : selfModel
|
||||
},
|
||||
set(val: unknown) {
|
||||
if (isGroup.value && Array.isArray(val)) {
|
||||
isLimitExceeded.value = false
|
||||
setup(props) {
|
||||
const { focus, isChecked, isDisabled, checkboxSize, model, handleChange } = useCheckbox(props)
|
||||
|
||||
if (checkboxGroup.min !== undefined && val.length < checkboxGroup.min) {
|
||||
isLimitExceeded.value = true
|
||||
}
|
||||
if (checkboxGroup.max !== undefined && val.length > checkboxGroup.max) {
|
||||
isLimitExceeded.value = true
|
||||
}
|
||||
|
||||
isLimitExceeded.value === false && checkboxGroup.changeEvent?.(val)
|
||||
} else {
|
||||
emit('update:modelValue', val)
|
||||
selfModel = val as boolean
|
||||
}
|
||||
},
|
||||
})
|
||||
const isChecked = computed(() => {
|
||||
const value = model.value
|
||||
if (Object.prototype.toString.call(value) === '[object Boolean]') {
|
||||
return Boolean(value)
|
||||
} else if (Array.isArray(value)) {
|
||||
return value.includes(props.label)
|
||||
} else if (value !== null && value !== undefined) {
|
||||
return value === props.trueLabel
|
||||
}
|
||||
})
|
||||
const isLimitDisabled = computed(() => {
|
||||
const max = checkboxGroup.max
|
||||
const min = checkboxGroup.min
|
||||
return !!(max || min) && (model.value.length >= max && !isChecked.value) ||
|
||||
(model.value.length <= min && isChecked.value)
|
||||
})
|
||||
const isDisabled = computed(() => {
|
||||
return isGroup.value
|
||||
? checkboxGroup.disabled || props.disabled || (elForm as any || {} as any).disabled || isLimitDisabled.value
|
||||
: props.disabled || (elForm as any || {} as any).disabled
|
||||
})
|
||||
const checkboxSize = computed(() => {
|
||||
const temCheckboxSize = props.size || elFormItemSize.value || (ELEMENT || {} as any).size
|
||||
return isGroup.value
|
||||
? checkboxGroup.checkboxGroupSize || temCheckboxSize
|
||||
: temCheckboxSize
|
||||
})
|
||||
|
||||
function addToStore() {
|
||||
if (
|
||||
Array.isArray(model.value) &&
|
||||
!model.value.includes(props.label)
|
||||
) {
|
||||
model.value.push(props.label)
|
||||
} else {
|
||||
model.value = props.trueLabel || true
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(e: InputEvent) {
|
||||
if (isLimitExceeded.value) return
|
||||
let value
|
||||
if ((e.target as HTMLInputElement).checked) {
|
||||
value = props.trueLabel === undefined ? true : props.trueLabel
|
||||
} else {
|
||||
value = props.falseLabel === undefined ? false : props.falseLabel
|
||||
}
|
||||
|
||||
emit('change', value, e)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, val => {
|
||||
elFormItem.changeEvent?.(val)
|
||||
})
|
||||
|
||||
props.checked && addToStore()
|
||||
|
||||
onMounted(() => {
|
||||
instance.vnode.el.setAttribute('aria-controls', props.controls)
|
||||
})
|
||||
setAria(props)
|
||||
|
||||
return {
|
||||
focus,
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { ref, computed, inject, getCurrentInstance, SetupContext } from 'vue'
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
inject,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { toTypeString } from '@vue/shared'
|
||||
import { UPDATE_MODEL_EVENT } from '@element-plus/utils/constants'
|
||||
import { ICheckboxGroupInstance, ICheckboxProps } from './checkbox'
|
||||
import { ICheckboxGroupInstance, ICheckboxProps, IArgs } from './checkbox'
|
||||
|
||||
export const useCheckboxGroup = () => {
|
||||
//todo: ELEMENT
|
||||
@ -8,14 +16,12 @@ export const useCheckboxGroup = () => {
|
||||
const elForm = inject('elForm', {})
|
||||
const elFormItem = inject('elFormItem', {}) as any
|
||||
const checkboxGroup = inject<ICheckboxGroupInstance>('CheckboxGroup', {})
|
||||
const focus = ref(false)
|
||||
const isGroup = computed(() => checkboxGroup && checkboxGroup.name === 'ElCheckboxGroup')
|
||||
const elFormItemSize = computed(() => {
|
||||
return (elFormItem || {} as any).elFormItemSize
|
||||
})
|
||||
return {
|
||||
isGroup,
|
||||
focus,
|
||||
checkboxGroup,
|
||||
elForm,
|
||||
ELEMENT,
|
||||
@ -24,11 +30,10 @@ export const useCheckboxGroup = () => {
|
||||
}
|
||||
}
|
||||
|
||||
export const useCheckbox = (props: ICheckboxProps, { emit }: SetupContext) => {
|
||||
const useModel = (props: ICheckboxProps) => {
|
||||
let selfModel = false
|
||||
const { elForm, isGroup, checkboxGroup, elFormItemSize, elFormItem, ELEMENT } = useCheckboxGroup()
|
||||
const instance = getCurrentInstance()
|
||||
const focus = ref(false)
|
||||
const { emit } = getCurrentInstance()
|
||||
const { isGroup, checkboxGroup } = useCheckboxGroup()
|
||||
const isLimitExceeded = ref(false)
|
||||
const store = computed(() => checkboxGroup ? checkboxGroup.modelValue.value : props.modelValue)
|
||||
const model = computed({
|
||||
@ -36,8 +41,8 @@ export const useCheckbox = (props: ICheckboxProps, { emit }: SetupContext) => {
|
||||
return isGroup.value ? store.value : props.modelValue !== undefined ? props.modelValue : selfModel
|
||||
},
|
||||
|
||||
set(val: any) {
|
||||
if (isGroup.value) {
|
||||
set(val: unknown) {
|
||||
if (isGroup.value && Array.isArray(val)) {
|
||||
isLimitExceeded.value = false
|
||||
|
||||
if (checkboxGroup.min !== undefined && val.length < checkboxGroup.min) {
|
||||
@ -49,12 +54,130 @@ export const useCheckbox = (props: ICheckboxProps, { emit }: SetupContext) => {
|
||||
|
||||
isLimitExceeded.value === false && checkboxGroup.changeEvent?.(val)
|
||||
} else {
|
||||
emit('update:modelValue', val)
|
||||
selfModel = val
|
||||
emit(UPDATE_MODEL_EVENT, val)
|
||||
selfModel = val as boolean
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
instance,
|
||||
model,
|
||||
isLimitExceeded,
|
||||
}
|
||||
}
|
||||
|
||||
const useCheckboxStatus = (props: ICheckboxProps, { model }: IArgs<typeof useModel>) => {
|
||||
const { isGroup, checkboxGroup, elFormItemSize, ELEMENT } = useCheckboxGroup()
|
||||
const focus = ref(false)
|
||||
const size = computed<string|undefined>(() => checkboxGroup.checkboxGroupSize || elFormItemSize || (ELEMENT || {}).size)
|
||||
const isChecked = computed(() => {
|
||||
const value = model.value
|
||||
if (toTypeString(value) === '[object Boolean]') {
|
||||
return Boolean(value)
|
||||
} else if (Array.isArray(value)) {
|
||||
return value.includes(props.label)
|
||||
} else if (value !== null && value !== undefined) {
|
||||
return value === props.trueLabel
|
||||
}
|
||||
})
|
||||
const checkboxSize = computed(() => {
|
||||
const temCheckboxSize = props.size || elFormItemSize.value || (ELEMENT || {} as any).size
|
||||
return isGroup.value
|
||||
? checkboxGroup.checkboxGroupSize || temCheckboxSize
|
||||
: temCheckboxSize
|
||||
})
|
||||
|
||||
return {
|
||||
isChecked,
|
||||
focus,
|
||||
size,
|
||||
checkboxSize,
|
||||
}
|
||||
}
|
||||
|
||||
const useDisabled = (
|
||||
props: ICheckboxProps,
|
||||
{ model, isChecked }: IArgs<typeof useModel> & IArgs<typeof useCheckboxStatus>,
|
||||
) => {
|
||||
const { elForm, isGroup, checkboxGroup } = useCheckboxGroup()
|
||||
const isLimitDisabled = computed(() => {
|
||||
const max = checkboxGroup.max
|
||||
const min = checkboxGroup.min
|
||||
return !!(max || min) && (model.value.length >= max && !isChecked.value) ||
|
||||
(model.value.length <= min && isChecked.value)
|
||||
})
|
||||
const isDisabled = computed(() => {
|
||||
return isGroup.value
|
||||
? checkboxGroup.disabled || props.disabled || (elForm as any || {} as any).disabled || isLimitDisabled.value
|
||||
: props.disabled || (elForm as any || {} as any).disabled
|
||||
})
|
||||
|
||||
return {
|
||||
isDisabled,
|
||||
isLimitDisabled,
|
||||
}
|
||||
}
|
||||
|
||||
const setStoreValue = (props: ICheckboxProps, { model }: IArgs<typeof useModel>) => {
|
||||
function addToStore() {
|
||||
if (
|
||||
Array.isArray(model.value) &&
|
||||
!model.value.includes(props.label)
|
||||
) {
|
||||
model.value.push(props.label)
|
||||
} else {
|
||||
model.value = props.trueLabel || true
|
||||
}
|
||||
}
|
||||
props.checked && addToStore()
|
||||
}
|
||||
|
||||
const useEvent = (props: ICheckboxProps, { isLimitExceeded }: IArgs<typeof useModel>) => {
|
||||
const { elFormItem } = useCheckboxGroup()
|
||||
const { emit } = getCurrentInstance()
|
||||
function handleChange(e: InputEvent) {
|
||||
if (isLimitExceeded.value) return
|
||||
const target = e.target as HTMLInputElement
|
||||
const value = target.checked
|
||||
? props.trueLabel ?? true
|
||||
: props.falseLabel ?? false
|
||||
|
||||
emit('change', value, e)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, val => {
|
||||
elFormItem.changeEvent?.(val)
|
||||
})
|
||||
|
||||
return {
|
||||
handleChange,
|
||||
}
|
||||
}
|
||||
|
||||
export const setAria = (props: ICheckboxProps) => {
|
||||
const instance = getCurrentInstance()
|
||||
onMounted(() => {
|
||||
instance.vnode.el.setAttribute('aria-controls', props.controls)
|
||||
})
|
||||
}
|
||||
|
||||
export const useCheckbox = (props: ICheckboxProps) => {
|
||||
const instance = getCurrentInstance()
|
||||
const { model, isLimitExceeded } = useModel(props)
|
||||
const { focus, size, isChecked, checkboxSize } = useCheckboxStatus(props, { model })
|
||||
const { isDisabled } = useDisabled(props, { model, isChecked })
|
||||
const { handleChange } = useEvent(props, { isLimitExceeded })
|
||||
|
||||
setStoreValue(props, { model })
|
||||
|
||||
return {
|
||||
instance,
|
||||
isChecked,
|
||||
isDisabled,
|
||||
checkboxSize,
|
||||
model,
|
||||
handleChange,
|
||||
focus,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user