Element source analysis -checkbox, feel logic like a single checkbox, look at it.

Checkbox Checkbox is also divided into three parts

  • Checkbox-group: applies to scenarios where multiple check boxes are bound to the same array. The selected items in this group are indicated by whether they are checked or not.
  • Checkbox: multiple selections.
  • Checkbox-button: multiple choices of button styles.

checkbox-group

This is equivalent to grouping checkboxes and checkboxButtons

structure

  <div class="el-checkbox-group" role="group" aria-label="checkbox-group">
    <! -- slot: used to receive checkbox or checkbox-button -->
    <slot></slot>
  </div>
Copy the code

Script part

1. Receive form component injection

Null by default, if used nested within the Form component and if the Form component injected elFormItem

    inject: {
      elFormItem: {
        default: ' '}}Copy the code

2. The injected content is used in computed

    computed: {
      // Control the size
      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize;
      },
      checkboxGroupSize() {
        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size; }}Copy the code

CheckboxGroupSize is used in checkbox and checkboxButton

(3) to monitor the value

    watch: {
      // Listen for value to look up the form component publish the el.form.change event expose value (array)
      value(value) {
        this.dispatch('ElFormItem'.'el.form.change', [value]); }}Copy the code

4. Properties of the props received

    props: {
      // Bind to v-model
      value: {},
      // Whether to disable
      disabled: Boolean.// Select the minimum length
      min: Number.// Maximum selected length
      max: Number./ / size
      size: String.// Border and background fill color
      fill: String.// Text color
      textColor: String
    }
Copy the code

Some properties are used by the checkbox and checkboxButton components

checkbox

structure

1. Outer label: Controls the outer style
  <label
    class="el-checkbox"
    :class="[ border && checkboxSize ? 'el-checkbox--' + checkboxSize : '', { 'is-disabled': isDisabled }, { 'is-bordered': border }, { 'is-checked': isChecked } ]"
    role="checkbox"
    :aria-checked="indeterminate ? 'mixed': isChecked"
    :aria-disabled="isDisabled"
    :id="id"
  >
 </label>
Copy the code
  • Role, ARIA-checked, ARIa-disabled: Barrier-free web application attributes (used for screen reading)
    • Aria-checked: True indicates that the element is checked, false indicates that the element is not checked, and mixed indicates that the element is selected and unselected.
2. Inner first SPAN selection box
    <span class="el-checkbox__input"
      :class="{ 'is-disabled': isDisabled, 'is-checked': isChecked, 'is-indeterminate': indeterminate, 'is-focus': focus }"
       aria-checked="mixed"
    >
      <span class="el-checkbox__inner"></span>
      <! TrueLabel or falseLabel -->
      <input
        .
        v-if="trueLabel || falseLabel"
        .
       >
      <! TrueLabel and falseLabel -->
      <input
        v-else
        .
       >
    </span>
Copy the code
  • The outer SPAN controls the unchecked style of the selection box
  • Hidden input simulated checkbox: has passed trueLable or falseLable and no two structures
3. The content corresponding to the second inner span- select box
    <span class="el-checkbox__label" v-if="$slots.default || label">
      <slot></slot>// There is a slot to display the content<template v-if=! "" $slots.default">{{label}}</template>
    </span>
Copy the code

Script part

Start with the life cycle
    created() {
      // Call addToStore if it is currently checked.
      this.checked && this.addToStore();
    },
    mounted() {
      // Not all of them are selected
      // Add the aria-Controls property to the indeTerminate element
      if (this.indeterminate) {
        // Controls corresponds to the id, representing the control relationship between elements
        this.$el.setAttribute('aria-controls'.this.controls); }}Copy the code

AddToStore method

addToStore() {
    // If model is an array and does not contain the current option, push the current option into model
    if (
        Array.isArray(this.model) &&
        this.model.indexOf(this.label) === - 1
    ) {
        this.model.push(this.label);
        // Otherwise the selected value or true is passed in
    } else {
        this.model = this.trueLabel || true; }}Copy the code
Some calculated properties
  • Selected or not
// Is selected
isChecked() {
    // Model is a Boolean type
    if ({}.toString.call(this.model) === '[object Boolean]') {
        // Return directly to model
        return this.model;
        // Array type
    } else if (Array.isArray(this.model)) {
        // The current label is true in model but not false
        return this.model.indexOf(this.label) > - 1;
        // The model exists returns whether it is congruent with the props trueLabel
    } else if (this.model ! = =null && this.model ! = =undefined) {
        return this.model === this.trueLabel; }}Copy the code
  • Whether to use nested in multiple select groups
// Look up the checkbox-group component and return true if it is found and false if it is not found
isGroup() {
    let parent = this.$parent;
    while (parent) {
        if(parent.$options.componentName ! = ='ElCheckboxGroup') {
            parent = parent.$parent;
        } else {
            this._checkboxGroup = parent;
            return true; }}return false;
}
Copy the code
  • Control several properties of the style
     isDisabled() {
        // Depending on the checkbox-group disabled props disabled form injection disabled
        return this.isGroup
          ? this._checkboxGroup.disabled || this.disabled || (this.elForm || {}).disabled
          : this.disabled || (this.elForm || {}).disabled;
      },

      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize;
      },

      checkboxSize() {
        // Depends on the size global configuration injected by the incoming size Form component
        const temCheckboxSize = this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
        // If it is wrapped by the checkbox-group component, the size of the checkbox-group component takes precedence
        return this.isGroup
          ? this._checkboxGroup.checkboxGroupSize || temCheckboxSize
          : temCheckboxSize;
      }
Copy the code
  • value
// checkbox-group Specifies the value or current value of the component instance
store() {
    return this._checkboxGroup ? this._checkboxGroup.value : this.value;
}
Copy the code
  • The value of v-model
      / / v - the value of the model
      model: {
        / / value
        get() {
          // If the current value has a value, selfModel will be used
          return this.isGroup
            ? this.store : this.value ! = =undefined
              ? this.value : this.selfModel;
        },
        / / assignment
        set(val) {
          // wrapped by checkbox-group
          if (this.isGroup) {
            this.isLimitExceeded = false;
            // If the assignment length is smaller than the checkbox-group min break limit
            (this._checkboxGroup.min ! = =undefined &&
              val.length < this._checkboxGroup.min &&
              (this.isLimitExceeded = true));
            // If the assignment length is greater than the Max limit of the checkbox-group
            (this._checkboxGroup.max ! = =undefined &&
              val.length > this._checkboxGroup.max &&
              (this.isLimitExceeded = true));
            // Find the checkbox-group component up without breaking the limit publish the input event to expose the val
            this.isLimitExceeded === false &&
            this.dispatch('ElCheckboxGroup'.'input', [val]);
          } else {
            // Val is not exposed by publishing the input event directly wrapped by the checkbox-group
            this.$emit('input', val);
            // Assign the selfModel value val
            this.selfModel = val; }}}Copy the code
  • IsLimitExceeded: Whether the limit is exceeded is related to the min and Max of the Checkbox-group
  • SelfModel: The model value that is not used in the multi-select group. The default is false

Input change event

      // Input change event
      handleChange(ev) {
        // Break the limit and return directly
        if (this.isLimitExceeded) return;
        let value;
        if (ev.target.checked) {
          // If trueLabel is selected and value is trueLabel, true is assigned
          value = this.trueLabel === undefined ? true : this.trueLabel;
        } else {
          // If falseLable is assigned to value, falseLabel is assigned to value if false is not selected
          value = this.falseLabel === undefined ? false : this.falseLabel;
        }
        // Publish the change method to expose the value and event objects
        this.$emit('change', value, ev);
        // If the dom is wrapped by the checkbox-group component after rendering, issue the change event to expose the value of the checkbox-group component instance (array).
        this.$nextTick((a)= > {
          if (this.isGroup) {
            this.dispatch('ElCheckboxGroup'.'change'[this._checkboxGroup.value]); }}); }Copy the code
Listen for value, related to form validation
    watch: {
      // Listen for value changes, and publish the el.form.change event to expose value if you go up to the form component
      value(value) {
        this.dispatch('ElFormItem'.'el.form.change', value); }}Copy the code
  • Dispatch: method blended in from mixins, looking up (specifying components, publishing specified events, exposing specified values)

    import Emitter from 'element-ui/src/mixins/emitter'
    Copy the code

checkbox-button

Basically the same as checkbox, with more button-related styles, activeStyle in computed is controlled by checkbox-group fill