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>
相关推荐
Aotman_1 天前
el-input textarea 禁止输入中文字符,@input特殊字符实时替换,光标位置保持不变
前端·javascript·vue.js·前端框架·es6
百思可瑞教育1 天前
在Vue项目中Axios发起请求时的小知识
前端·javascript·vue.js·北京百思教育
qq_12498707531 天前
基于node.js+vue的医院陪诊系统的设计与实现(源码+论文+部署+安装)
前端·vue.js·node.js·毕业设计
科兴第一吴彦祖1 天前
在线会议系统是一个基于Vue3 + Spring Boot的现代化在线会议管理平台,集成了视频会议、实时聊天、AI智能助手等多项先进技术。
java·vue.js·人工智能·spring boot·推荐算法
沙尘暴炒饭1 天前
前端vue使用canvas封装图片标注功能,鼠标画矩形框,标注文字 包含下载标注之后的图片
前端·vue.js·计算机外设
百思可瑞教育1 天前
Vue中使用keep-alive实现页面前进刷新、后退缓存的完整方案
前端·javascript·vue.js·缓存·uni-app·北京百思可瑞教育
前端码虫1 天前
2.9Vue创建项目(组件)的补充
javascript·vue.js·学习
BillKu1 天前
Vue3中app.mount(“#app“)应用挂载原理解析
javascript·vue.js·css3
VueVirtuoso1 天前
SaaS 建站从 0 到 1 教程:Vue 动态域名 + 后端子域名管理 + Nginx 配置
前端·vue.js·nginx
祈祷苍天赐我java之术1 天前
Vue 整体框架全面解析
前端·javascript·vue.js