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>
相关推荐
计算机学姐3 小时前
基于SpringBoot的小型民营加油站管理系统
java·vue.js·spring boot·后端·mysql·spring·tomcat
sunbyte5 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Expanding Cards (展开式卡片)
javascript·vue.js·ecmascript
重生之后端学习6 小时前
02-前端Web开发(JS+Vue+Ajax)
java·开发语言·前端·javascript·vue.js
黄鹂绿柳9 小时前
Vue+Vite学习笔记
vue.js·笔记·学习
来自星星的坤9 小时前
【Vue 3 + Vue Router 4】如何正确重置路由实例(resetRouter)——避免“VueRouter is not defined”错误
前端·javascript·vue.js
清风细雨_林木木15 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
繁依Fanyi17 小时前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
codelxy17 小时前
vue引用cesium,解决“Not allowed to load local resource”报错
javascript·vue.js
Zww089118 小时前
el-dialog鼠标在遮罩层松开会意外关闭,教程图文并茂
javascript·vue.js·计算机外设
sunbyte18 小时前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | 页面布局 与 Vue Router 路由配置
前端·javascript·vue.js·tailwindcss