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

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

技术杂谈小彩虹2021-08-19 6:07:45300A+A-

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

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

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

checkbox-group

相当于把checkbox和checkboxButton形成一个组

结构

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

script部分

1.接收form组件注入

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

    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组件会用到

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混入进来的方法,向上寻找(指定组件,发布指定事件,暴露指定值)

    import Emitter from 'element-ui/src/mixins/emitter'
    

checkbox-button

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

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们