Element-ui 之 Checkbox-Group 组件的源码分析

一. Checkbox-Group 组件提供的属性和事件

1.1 属性

以下是 checkbox-Group 组件提供的属性:

参数 说明 类型 可选值 默认值
value / v-model 绑定值 array -- --
size 多选框组尺寸,仅对按钮形式的 Checkbox 或带有边框的 Checkbox 有效 string medium / small / mini --
disabled 是否禁用 boolean -- false
min 可被勾选的 checkbox 的最小数量 number -- --
max 可被勾选的 checkbox 的最大数量 number -- --
text-color 按钮形式的 Checkbox 激活时的文本颜色 string -- #ffffff
fill 按钮形式的 Checkbox 激活时的填充色和边框色 string -- #409EFF

1.2 事件

事件名称 说明 回调参数
change 当绑定值变化时触发的事件 更新后的值

二. 按照步骤去实现 Checkbox-Group 组件的属性和事件

  1. 注册组件。
  2. checkbox-group 的基本 template 部分。
  3. 绑定值 v-model 的处理。
  4. 禁用 disabled 属性的处理。
  5. 可被勾选的最小数量 min,最大数量 max 的处理。
  6. 尺寸 size 属性的处理。
  7. 接收 text-colorfill 属性,用于后续讲解的 checkbox-button 组件。

三. Checkbox 组件属性和事件的具体实现

3.1 注册组件

新建一个 checkbox-group.vue 文件,设置组件的 namecomponentName 都为 ElCheckboxGroup

main.js 文件里面引入这个组件,并且使用 Vue.component 来全局注册这个组件。

3.2 checkbox-group 的基本 template 部分

html 复制代码
<template>
  <div class="el-checkbox-group" role="group" aria-label="checkbox-group">
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: 'ElCheckboxGroup',

  componentName: 'ElCheckboxGroup',
}
</script>
  • 一个 div 标签内部包裹父组件内部传过来的内容,div 设置属性 role="group"aria-label="checkbox-group"
  • aria-label 属性为无障碍 API,用来给元素增加标签描述,接收字符串为参数。

3.3 绑定值 v-model 的处理

实现步骤:

  1. 新建一个文件,文件内部引入 checkbox-group 组件,并且在 checkbox-group 组件内容写入三个 checkbox 组件,给 checkbox 组件增加 label 属性,checkbox-group 组件增加 v-model 绑定值。
html 复制代码
<template>
  <el-checkbox-group v-model="checkList">
    <el-checkbox :label="1">备选项1</el-checkbox>
    <el-checkbox :label="2">备选项2</el-checkbox>
    <el-checkbox :label="3">备选项3</el-checkbox>
  </el-checkbox-group>
</template>
<script>
export default {
  data() {
    return {
      checkList: [1]
    }
  }
}
</script>
  1. checkbox-group 组件中用 props 使用默认的 value 属性用来接收 v-model 的绑定值。
js 复制代码
props: {
  value: {}
}
  1. checkbox 组件中设置计算属性 isGroup 来判断该多选框是否被包含在多选框组里面。如果被包含在多选框组里面,则用变量 _checkboxGroup 保存多选框组的信息。
js 复制代码
isGroup() {
  // parent 变量保存组件的父级元素信息
  let parent = this.$parent;
  while (parent) {
    if (parent.$options.componentName !== 'ElCheckboxGroup') {
      // 如果父级的 componentName 不是 ElCheckboxGroup 则继续向上查找
      parent = parent.$parent;
    } else {
      // 如果父级的 componentName 是 ElCheckboxGroup
      // 用变量 _checkboxGroup 保存父级信息,并且返回 true
      this._checkboxGroup = parent;
      return true;
    }
  }
  return false;
},
  1. checkbox 组件中设置计算属性 store 根据多选框还是多选框组来获取不同的 value 值。判断 _checkboxGroup 是否存在,如果存在,则取多选框组的值,否则取多选框的值。
js 复制代码
store() {
  return this._checkboxGroup ? this._checkboxGroup.value : this.value;
},
  1. 修改计算属性 modelgettersetter 方法,新增判断如果是多选框组,则获取/设置多选框组的值,否则获取/设置多选框的值。

(1)getter 方法修改成如果 isGrouptrue,则取计算属性 store 的值,否则还是取之前 checkboxvalue 值。

js 复制代码
computed: {
  ...
  model: {
    get() {
      return this.isGroup
        ? this.store : this.value !== undefined
          ? this.value : this.selfModel;
    },
  }
}

(2)setter 方法修改成如果 isGrouptrue,则向上查找并触发多选框组的 input 方法。

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

mixins: [Emitter],

computed: {
  ...
  model: {
    set(val) {
      if (this.isGroup) {
        this.dispatch('ElCheckboxGroup', 'input', [val]);
      } else {
        this.$emit('input', val);
        this.selfModel = val;
      }
    },
  }
}
  1. handleChange 方法中增加如果是多选框组,则触发 checkbox-group 组件的 change 方法。
js 复制代码
methods: {
  handleChange(ev) {
    ...
    // 需要放在 nextTick 中,否则得到的是上一次的值
    this.$nextTick(() => {
      if (this.isGroup) {
        this.dispatch('ElCheckboxGroup', 'change', [this._checkboxGroup.value]);
      }
    });
  }
}
  1. 选中状态在之前讲 checkbox 组件时已经处理过为数组时的选中了。

3.4 禁用 disabled 属性的处理

实现步骤:

  1. 在引入 checkbox-group 组件的文件中增加 disabled 属性。
html 复制代码
<template>
  <el-checkbox-group v-model="checkList" disabled>
    <el-checkbox :label="1">备选项1</el-checkbox>
    <el-checkbox :label="2">备选项2</el-checkbox>
    <el-checkbox :label="3">备选项3</el-checkbox>
  </el-checkbox-group>
</template>
<script>
export default {
  data() {
    return {
      checkList: [1]
    }
  },
}
</script>
  1. checkbox-group 组件中用 props 接收 disabled 属性。
js 复制代码
props: {
  disabled: Boolean,
}
  1. 修改 checkbox 组件中的计算属性 isDisabled,判断 isGroup 是否为 true,如果为 true 则获取多选框组的 disabled 属性。
js 复制代码
computed: {
  isDisabled() {
    return this.isGroup
      ? this._checkboxGroup.disabled || this.disabled
      : this.disabled
  },
}

3.5 可被勾选的最小数量 min,最大数量 max 的处理

实现步骤:

  1. 引入 checkbox-group 组件的文件中增加最小数量 min,最大数量 max 这两个属性。
html 复制代码
<template>
  <el-checkbox-group v-model="checkList" :min="1" :max="2">
    <el-checkbox :label="1">备选项1</el-checkbox>
    <el-checkbox :label="2">备选项2</el-checkbox>
    <el-checkbox :label="3">备选项3</el-checkbox>
  </el-checkbox-group>
</template>
<script>
export default {
  data() {
    return {
      checkList: [1]
    }
  },
}
</script>
  1. checkbox-group 组件中使用 props 接收 minmax
js 复制代码
props: {
  min: Number,
  max: Number,
}
  1. checkbox 组件的 data 中增加变量 isLimitExceeded,用于判断勾选数量是否超出限制。
js 复制代码
data() {
  return {
    ...
    isLimitExceeded: false
  }
}
  1. 修改计算属性 model,判断如果超出了最小、最大限制则将变量 isLimitExceeded 设置为 true,并且不能触发 checkbox-group 组件的 input 方法。
js 复制代码
computed: {
  ...
  model: {
    ...
    set(val) {
      if (this.isGroup) {
        (this._checkboxGroup.min !== undefined &&
          val.length < this._checkboxGroup.min &&
          (this.isLimitExceeded = true));

        (this._checkboxGroup.max !== undefined &&
          val.length > this._checkboxGroup.max &&
          (this.isLimitExceeded = true));

        this.isLimitExceeded === false &&
        this.dispatch('ElCheckboxGroup', 'input', [val]);
      } else {
        this.$emit('input', val);
        this.selfModel = val;
      }
    }
  }
}
  1. handleChange 方法中增加判断如果 isLimitExceeded 已经超出了限制,则不能触发 change 方法。
js 复制代码
methods: {
  handleChange(ev) {
    if (this.isLimitExceeded) return;
    ...
  }
}
  1. 增加计算属性 isLimitDisabled,判断此次点击之后该 checkbox 是否会被禁止点击。如果 minmax 有任意属性存在,分两种情况:
    第一种:当已选数量大于等于最大限制数量时,禁用没有选中的 checkbox
    第二种:当已选数量小于等于最小限制数量时,禁用已经选中的 checkbox
js 复制代码
computed: {
  isLimitDisabled() {
    const { max, min } = this._checkboxGroup;
    return !!(max || min) &&
      (this.model.length >= max && !this.isChecked) ||
      (this.model.length <= min && this.isChecked);
  },
}
  1. 修改计算属性 isDisabled,增加 isLimitDisabled 的判断。
js 复制代码
computed: {
  ...
  isDisabled() {
    return this.isGroup
      ? this._checkboxGroup.disabled || this.disabled || this.isLimitDisabled
      : this.disabled
  },
  ...
}

3.6 尺寸 size 属性的处理

实现步骤:

  1. 引入 checkbox-group 组件的文件中增加 size 属性,size="mini",并且在每一个 checkbox 上面增加 border 属性。
html 复制代码
<template>
  <el-checkbox-group v-model="checkList" size="mini">
    <el-checkbox :label="1" border>备选项1</el-checkbox>
    <el-checkbox :label="2" border>备选项2</el-checkbox>
    <el-checkbox :label="3" border>备选项3</el-checkbox>
  </el-checkbox-group>
</template>
<script>
export default {
  data() {
    return {
      checkList: [1]
    }
  },
}
</script>
  1. checkbox-group 组件中使用 props 获取传入的 size 属性。
js 复制代码
props: {
  size: String,
}
  1. checkbox-group 组件中设置计算属性 checkboxGroupSize 监听 size 属性的改变。
js 复制代码
computed: {
  checkboxGroupSize() {
    return this.size;
  }
}
  1. checkbox 组件中修改计算属性 checkboxSize,如果 isGrouptrue,优先获取 checkbox-group 传入的 size
js 复制代码
computed: {
  ...
  checkboxSize() {
    return this.isGroup
      ? this._checkboxGroup.checkboxGroupSize || this.size
      : this.size;
  }
}

3.7 接收 text-color 和 fill 属性,用于后续讲解的 Checkbox-button 组件

checkbox-group 组件中使用 props 接收传入的 text-colorfill 属性,这两个属性是 checkbox-button 组件使用到的。

js 复制代码
props: {
  ...
  fill: String,
  textColor: String
}

四. 整体代码详解

包含 Checkbox-GroupForm 组件相互作用的部分。

html 复制代码
<template>
  <div class="el-checkbox-group" role="group" aria-label="checkbox-group">
    <slot></slot>
  </div>
</template>
<script>
import Emitter from '../../utils/mixins/emitter';

export default {
  name: 'ElCheckboxGroup',
  
  mixins: [Emitter],
  
  inject: {
    elFormItem: {
      default: ''
    }
  },

  componentName: 'ElCheckboxGroup',
  
  props: {
    value: {}, // checkbox-group 的 value 值
    disabled: Boolean,
    min: Number, // 最小限制数量
    max: Number, // 最大限制数量
    size: String,
    fill: String, // checkbox-button 组件样式用到的 fill 填充
    textColor: String // checkbox-button 组件样式用到的 textColor 文字颜色
  },
  
  computed: {
    // 获取 Form-Item 组件的 elFormItemSize 变量
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    // Checkbox-Group 组件的尺寸计算
    checkboxGroupSize() {
      // 优先级:group-size > Form-Item > Form
      return this.size || this._elFormItemSize;
    }
  },
  
  watch: {
    value(value) {
      // 监听 value 值的变化,当 value 值改变时,向 Form-Item 组件派发 el.form.change 自定义事件
      this.dispatch('ElFormItem', 'el.form.change', [value]);
    }
  }
}
</script>
相关推荐
码力码力我爱你1 小时前
QT + WebAssembly + Vue环境搭建
vue.js·vue·wasm·webassembly·emscripten
洛千陨1 小时前
element-plus弹窗内分页表格保留勾选项
前端·javascript·vue.js
完球了2 小时前
【Day02-JS+Vue+Ajax】
javascript·vue.js·笔记·学习·ajax
前端没钱2 小时前
若依Nodejs后台、实现90%以上接口,附体验地址、源码、拓展特色功能
前端·javascript·vue.js·node.js
纳尼亚awsl3 小时前
无限滚动组件封装(vue+vant)
前端·javascript·vue.js
cc蒲公英3 小时前
vue2中使用vue-office库预览pdf /docx/excel文件
前端·vue.js
小兔崽子去哪了4 小时前
Element plus 图片手动上传与回显
前端·javascript·vue.js
A阳俊yi4 小时前
Vue(13)——router-link
前端·javascript·vue.js
4triumph4 小时前
Vue.js教程笔记
前端·vue.js
程序员大金5 小时前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis