Moment For Technology

[Element Plus source code] Checkbox

Posted on Oct. 10, 2023, 8:38 p.m. by Nina Butcher
Category: The front end Tag: vue.js element

I. Component introduction

Website links: the Checkbox component | Element (gitee. IO)

The Checkbox component is one of the most commonly used components on a daily basis and is used by users to check options.

1.1 attributes

1.1.1 Value binding correlation

  • Model-value/V-model: string/number/ Boolean type, binding value;
  • Label: string/number/Boolean/object, value when selected, incheckbox-groupOr the binding object type isarrayAvailable at the time;
  • True-lable: string/number, the value when selected.
  • False -label: string/number, if not selected.
  • Checked: Boolean Indicates the Boolean type.

1.1.2 Display related

  • Disabled: Boolean indicates whether to disable.
  • Border: Boolean, whether to display a border;
  • Name: string, native name attribute;
  • Size: string. This parameter is optional. This parameter is valid only in the border statemedium/small/mini;
  • Indeterminate: Boolean, set semi-selected state, set style only, default false;

1.2 event

  • "Change" : triggered when the binding value changes.

Second, source code analysis

2.1 the template

template// Use the lable labellabel
    :id="id"
    class="el-checkbox"
    :class="[ border  checkboxSize ? 'el-checkbox--' + checkboxSize : '', { 'is-disabled': isDisabled }, { 'is-bordered': border }, { 'is-checked': isChecked } ]"
    :aria-controls="indeterminate ? controls : null"
  // Select the box sectionspan
      class="el-checkbox__input"
      :class="{ 'is-disabled': isDisabled, 'is-checked': isChecked, 'is-indeterminate': indeterminate, 'is-focus': focus }"
      :tabindex="indeterminate ? 0 : false"
      :role="indeterminate ? 'checkbox' : false"
      :aria-checked="indeterminate ? 'mixed' : false"
    // Used to control checked/unchecked stylesspan class="el-checkbox__inner"/span// With trueLable/falseLabel, add custom true-value/false-value attributes to inputinput
        v-if="trueLabel || falseLabel"
        v-model="model"
        :checked="isChecked"
        class="el-checkbox__original"
        type="checkbox"
        :aria-hidden="indeterminate ? 'true' : 'false'"
        :name="name"
        :disabled="isDisabled"
        :true-value="trueLabel"
        :false-value="falseLabel"
        @change="handleChange"
        @focus="focus = true"
        @blur="focus = false"
      
      input
        v-else
        v-model="model"
        class="el-checkbox__original"
        type="checkbox"
        :aria-hidden="indeterminate ? 'true' : 'false'"
        :disabled="isDisabled"
        :value="label"
        :name="name"
        @change="handleChange"
        @focus="focus = true"
        @blur="focus = false"
      
    /span// The text partspan v-if="$slots.default || label" class="el-checkbox__label"
      slot/slot
      template v-if=! "" $slots.default"{{ label }}/template
    /span
  /label
/template
Copy the code

2.2 the script

// checkbox.vue
// Some core code
import { useCheckbox } from './useCheckbox'

export default defineComponent({
  setup(props) {
    // Call the useCheckbox method
    return useCheckbox(props)
  },
})
Copy the code
// useCheckbox.ts

export const useCheckboxGroup = () =  {
  const ELEMENT = useGlobalConfig()
  // checkbox Inject data when used in form/checkbox-group
  const elForm = inject(elFormKey, {} as ElFormContext)
  const elFormItem = inject(elFormItemKey, {} as ElFormItemContext)
  const checkboxGroup = injectICheckboxGroupInstance('CheckboxGroup', {})
  // Whether the mode is group
  const isGroup = computed(() = checkboxGroup  checkboxGroup? .name ==='ElCheckboxGroup')
  / / form - the size of the item
  const elFormItemSize = computed(() =  {
    return elFormItem.size
  })
  return {
    isGroup,
    checkboxGroup,
    elForm,
    ELEMENT,
    elFormItemSize,
    elFormItem,
  }
}

// 
const useModel = (props: ICheckboxProps) =  {
  const selfModel = ref(false)
  const { emit } = getCurrentInstance()
  const { isGroup, checkboxGroup } = useCheckboxGroup()
  const isLimitExceeded = ref(false)
  // In group mode, set the group binding value; For standalone use, take the passed modelValue value
  const store = computed(() = checkboxGroup ? checkboxGroup.modelValue? .value : props.modelValue)// Sets the calculation properties of getter and setter
  const model = computed({
    get() {
      return isGroup.value
        ? store.value
        : props.modelValue ?? selfModel.value
    },

    set(val: unknown) {
      if (isGroup.value  Array.isArray(val)) {
        // In chebox-group mode, data is in array format
        isLimitExceeded.value = false
        // Check whether the range of optional numbers set by checbox-group is exceeded
        if(checkboxGroup.min ! = =undefined  val.length  checkboxGroup.min.value) {
          isLimitExceeded.value = true
        }
        if(checkboxGroup.max ! = =undefined  val.length  checkboxGroup.max.value) {
          isLimitExceeded.value = true
        }

        isLimitExceeded.value === false checkboxGroup? .changeEvent? .(val) }else {
        // Emit the V-model event, update:modelValue
        emit(UPDATE_MODEL_EVENT, val)
        selfModel.value = val as boolean}}})return {
    model,
    isLimitExceeded,
  }
}

/ / the checkbox state
const useCheckboxStatus = (props: ICheckboxProps, { model }: PartialReturnTypetypeof useModel) =  {
  const { isGroup, checkboxGroup, elFormItemSize, ELEMENT } = useCheckboxGroup()
  const focus = ref(false)
  const size = computedstring | undefined (() = checkboxGroup? .checkboxGroupSize? .value || elFormItemSize.value || ELEMENT.size)// Whether it is selected
  const isChecked = computed(() =  {
    const value = model.value
    // Judgment processing under various data types
    if (toTypeString(value) === '[object Boolean]') {
      // Boolean that returns model.value directly
      return value
    } else if (Array.isArray(value)) {
      // Check whether the array contains the lable of the current checkbox
      return value.includes(props.label)
    } else if(value ! = =null value ! = =undefined) {
      // Other data types to determine if they are equal to the trueLabel passed in
      return value === props.trueLabel
    }
  })
  // size: passed size  form-item size  global configuration size
  const checkboxSize = computed(() =  {
    const temCheckboxSize = props.size || elFormItemSize.value || ELEMENT.size
    returnisGroup.value ? checkboxGroup? .checkboxGroupSize? .value || temCheckboxSize : temCheckboxSize })return {
    isChecked,
    focus,
    size,
    checkboxSize,
  }
}

// Whether to disable
const useDisabled = (
  props: ICheckboxProps,
  { model, isChecked }: PartialReturnTypetypeof useModel  PartialReturnTypetypeof useCheckboxStatus,
) =  {
  const { elForm, isGroup, checkboxGroup } = useCheckboxGroup()
  // Disable judgment due to optional quantity range
  const isLimitDisabled = computed(() =  {
    constmax = checkboxGroup.max? .valueconstmin = checkboxGroup.min? .valuereturn!!!!! (max || min)  (model.value.length = max  ! isChecked.value) || (model.value.length = min  isChecked.value) })// In group mode: Disabeld of the group  Disabled of itself  Disabled of number limit
  // Use alone: prop disabled  form disabled
  const isDisabled = computed(() =  {
    const disabled = props.disabled || elForm.disabled
    returnisGroup.value ? checkboxGroup.disabled? .value || disabled || isLimitDisabled.value : props.disabled || elForm.disabled })return {
    isDisabled,
    isLimitDisabled,
  }
}

// 
const setStoreValue = (props: ICheckboxProps, { model }: PartialReturnTypetypeof useModel) =  {
  function addToStore() {
    If the array does not contain the label of the current checkbox, push the label of the current checkbox into the array
    if (
      Array.isArray(model.value)  ! model.value.includes(props.label) ) { model.value.push(props.label) }else {
      model.value = props.trueLabel || true}}// addToStore is executed when selected
  props.checked  addToStore()
}

/ / event
const useEvent = (props: ICheckboxProps, { isLimitExceeded }: PartialReturnTypetypeof useModel) =  {
  const { elFormItem } = useCheckboxGroup()
  const { emit } = getCurrentInstance()
  // change handler function
  function handleChange(e: InputEvent) {
    if (isLimitExceeded.value) return
    const target = e.target as HTMLInputElement
    const value = target.checked
      ? props.trueLabel ?? true
      : props.falseLabel ?? false
    // Throw the change event outward
    emit('change', value, e)
  }

  watch(() =  props.modelValue, val= { elFormItem.formItemMitt? .emit('el.form.change', [val])
  })

  return {
    handleChange,
  }
}

// useCheckbox is called in checkbox.vue
export const useCheckbox = (props: ICheckboxProps) =  {
  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 {
    isChecked,
    isDisabled,
    checkboxSize,
    model,
    handleChange,
    focus,
    size,
  }
}
Copy the code

2.3 summarize

  1. checkbox.vueThe script part of the script is mainly calleduseCheckboxMethod, rather than writing all property methods in the setup function, this is more elegant and concise, divided functions by function, corresponding data and methods in the same function, also introduced by VUe3composition-apiThe original intention of the formula;
  2. The checkbox's model value can be used alonestring/boolean/numberType; But in thecheckbox-groupIn the checkbox-group mode, the model value is in the form of an array, and the linkage between a single Checkbox and a global Checkbox-group is achieved through getter and setter methods.
Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.