拜读及分析Element源码-checkbox多选框组件篇

element源码分析-checkbox多选框,感受逻辑跟单选框很像,来看看吧。javascript

checkbox多选框和单选框同样也分为三部分html

  • checkbox-group:适用于多个勾选框绑定到同一个数组的情景,经过是否勾选来表示这一组选项中选中的项。
  • checkbox:多选。
  • checkbox-button: 按钮样式的多选。

checkbox-group

至关于把checkbox和checkboxButton造成一个组java

结构

<div class="el-checkbox-group" role="group" aria-label="checkbox-group">
    <!-- 插槽:用来接收checkbox或checkbox-button -->
    <slot></slot>
  </div>
复制代码

script部分

1.接收form组件注入

默认为空,若在form组件中嵌套使用并form组件注入了elFormItem则有值element-ui

inject: {
      elFormItem: {
        default: ''
      }
    }
复制代码

2.注入的内容会在computed中使用

computed: {
      // 控制大小
      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize;
      },
      checkboxGroupSize() {
        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
      }
    }
复制代码

checkboxGroupSize会在checkboxcheckboxButton中用到数组

3.监听value

watch: {
      // 监听value 向上寻找form组件发布el.form.change事件暴露value(数组)
      value(value) {
        this.dispatch('ElFormItem', 'el.form.change', [value]);
      }
    }
复制代码

4.props接收的属性

props: {
      // 与v-model绑定
      value: {},
      // 是否禁用
      disabled: Boolean,
      // 最少勾选长度
      min: Number,
      // 最大勾选长度
      max: Number,
      // 大小
      size: String,
      // 边框及背景填充色
      fill: String,
      // 文字颜色
      textColor: String
    }
复制代码

有些属性checkbox和checkboxButton组件会用到dom

checkbox

结构

1.外层label: 控制外层样式
<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>
复制代码
  • role,aria-checked,aria-disabled:无障碍网页应用属性(用于读屏)
    • aria-checked: true表明选中,false表明未选中,mixed表明:元素指示选定和未选择状态 。
2.内层第一个span选择框
<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或falseLabel时展现 -->
      <input ... v-if="trueLabel || falseLabel" ... >
      <!-- 无trueLabel和falseLabel时展现 -->
      <input v-else ... >
    </span>
复制代码
  • 外层span控制选择框的选中未被选中样式
  • 隐藏的input模拟checkbox: 分为有传入trueLable或falseLable与无两种结构
3.内层第二个span-选择框对应的内容
<span class="el-checkbox__label" v-if="$slots.default || label">
      <slot></slot>
       // 有插槽内容显示插槽 无直接显示label
      <template v-if="!$slots.default">{{label}}</template>
    </span>
复制代码

script部分

从生命周期开始
created() {
      // 若是当前勾选 调用addToStore(至关于选中与model值对应)
      this.checked && this.addToStore();
    },
    mounted() {
      // 若是有被选中又不是全选
      // 为indeterminate元素 添加aria-controls 属性
      if (this.indeterminate) {
        // controls对应id,表示元素之间的控制关系
        this.$el.setAttribute('aria-controls', this.controls);
      }
    }
复制代码

addToStore方法源码分析

addToStore() {
    // 若是model是数组而且不包含当前的选项,把当前选项push到model中
    if (
        Array.isArray(this.model) &&
        this.model.indexOf(this.label) === -1
    ) {
        this.model.push(this.label);
        // 不然 为传入选中值或true
    } else {
        this.model = this.trueLabel || true;
    }
}
复制代码
一些计算属性
  • 是否被选中
// 是否被选中
isChecked() {
    // model是Boolean类型
    if ({}.toString.call(this.model) === '[object Boolean]') {
        // 直接返回model
        return this.model;
        // 数组类型
    } else if (Array.isArray(this.model)) {
        // 当前的label在model中为true不在为false
        return this.model.indexOf(this.label) > -1;
        // model存在 返回是否与props的trueLabel全等
    } else if (this.model !== null && this.model !== undefined) {
        return this.model === this.trueLabel;
    }
}
复制代码
  • 是否在多选组中嵌套使用
// 向上找checkbox-group组件找到返回true 未找到返回false
isGroup() {
    let parent = this.$parent;
    while (parent) {
        if (parent.$options.componentName !== 'ElCheckboxGroup') {
            parent = parent.$parent;
        } else {
            this._checkboxGroup = parent;
            return true;
        }
    }
    return false;
}
复制代码
  • 控制样式的几个属性
isDisabled() {
        // 取决于 checkbox-group的disabled props的disabled form注入的disabled
        return this.isGroup
          ? this._checkboxGroup.disabled || this.disabled || (this.elForm || {}).disabled
          : this.disabled || (this.elForm || {}).disabled;
      },

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

      checkboxSize() {
        // 取决于传入的size form组件注入的size 全局配置size
        const temCheckboxSize = this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
        // 若是被checkbox-group组件包裹,优先checkbox-group组件的size
        return this.isGroup
          ? this._checkboxGroup.checkboxGroupSize || temCheckboxSize
          : temCheckboxSize;
      }
复制代码
  • value
// checkbox-group组件实例的value或当前value
store() {
    return this._checkboxGroup ? this._checkboxGroup.value : this.value;
}
复制代码
  • v-model对应的值
// v-model的值
      model: {
        // 取值
        get() {
          // 被checkbox-group包裹则取store,当前value有值则取value不然selfModel
          return this.isGroup
            ? this.store : this.value !== undefined
              ? this.value : this.selfModel;
        },
        // 赋值
        set(val) {
          // 被checkbox-group包裹
          if (this.isGroup) {
            this.isLimitExceeded = false;
            // 若赋值长度小于checkbox-group的min 突破限制
            (this._checkboxGroup.min !== undefined &&
              val.length < this._checkboxGroup.min &&
              (this.isLimitExceeded = true));
            // 若赋值长度大于checkbox-group的max 突破限制
            (this._checkboxGroup.max !== undefined &&
              val.length > this._checkboxGroup.max &&
              (this.isLimitExceeded = true));
            // 没有突破限制 向上找到checkbox-group组件发布input事件暴露val(数组形式)
            this.isLimitExceeded === false &&
            this.dispatch('ElCheckboxGroup', 'input', [val]);
          } else {
            // 没有被checkbox-group包裹 直接发布input事件暴露val
            this.$emit('input', val);
            // 给selfModel赋值val
            this.selfModel = val;
          }
        }
      }
复制代码
  • isLimitExceeded: 是否突破限制 与checkbox-group的min和max有关
  • selfModel: 没有在多选组中使用的model值,默认false

input的change事件

// input的change事件
      handleChange(ev) {
        // 突破限制 直接return
        if (this.isLimitExceeded) return;
        let value;
        if (ev.target.checked) {
          // 被选中 给value赋值 有trueLabel则赋值trueLabel 无则赋值true
          value = this.trueLabel === undefined ? true : this.trueLabel;
        } else {
          // 未被选中 给value赋值 有falseLable则赋值falseLabel 无则false
          value = this.falseLabel === undefined ? false : this.falseLabel;
        }
        // 发布change方法暴露value及和event对象
        this.$emit('change', value, ev);
        // dom渲染完成后 若是被checkbox-group组件包裹 则发布change事件,暴露checkbox-group组件实例的value(数组)
        this.$nextTick(() => {
          if (this.isGroup) {
            this.dispatch('ElCheckboxGroup', 'change', [this._checkboxGroup.value]);
          }
        });
      }
复制代码
监听value,与表单验证相关
watch: {
      // 监听value变化,向上找到form组件则发布el.form.change事件暴露出value
      value(value) {
        this.dispatch('ElFormItem', 'el.form.change', value);
      }
    }
复制代码
  • dispatch: 从mixins混入进来的方法,向上寻找(指定组件,发布指定事件,暴露指定值)ui

    import Emitter from 'element-ui/src/mixins/emitter'
    复制代码

checkbox-button

与checkbox基本一致,多了button相关样式,computed中的activeStyle,受checkbox-group的fill控制this

相关文章
相关标签/搜索