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

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

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

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

checkbox-group

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

结构

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

script部分

1.接收form组件注入

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

1
2
3
4
5
inject: {
elFormItem: {
default: ''
}
}

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

1
2
3
4
5
6
7
8
9
computed: {
// 控制大小
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
checkboxGroupSize() {
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
}
}

checkboxGroupSize会在checkboxcheckboxButton中用到

3.监听value

1
2
3
4
5
6
watch: {
// 监听value 向上寻找form组件发布el.form.change事件暴露value(数组)
value(value) {
this.dispatch('ElFormItem', 'el.form.change', [value]);
}
}

4.props接收的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
props: {
// 与v-model绑定
value: {},
// 是否禁用
disabled: Boolean,
// 最少勾选长度
min: Number,
// 最大勾选长度
max: Number,
// 大小
size: String,
// 边框及背景填充色
fill: String,
// 文字颜色
textColor: String
}

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

checkbox

结构

1.外层label: 控制外层样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <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选择框
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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-选择框对应的内容
1
2
3
4
5
<span class="el-checkbox__label" v-if="$slots.default || label">
<slot></slot>
// 有插槽内容显示插槽 无直接显示label
<template v-if="!$slots.default">{{label}}</template>
</span>

script部分

从生命周期开始
1
2
3
4
5
6
7
8
9
10
11
12
created() {
// 如果当前勾选 调用addToStore(相当于选中与model值对应)
this.checked && this.addToStore();
},
mounted() {
// 如果有被选中又不是全选
// 为indeterminate元素 添加aria-controls 属性
if (this.indeterminate) {
// controls对应id,表示元素之间的控制关系
this.$el.setAttribute('aria-controls', this.controls);
}
}

addToStore方法

1
2
3
4
5
6
7
8
9
10
11
12
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;
}
}
一些计算属性
  • 是否被选中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 是否被选中
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;
}
}
  • 是否在多选组中嵌套使用
1
2
3
4
5
6
7
8
9
10
11
12
13
// 向上找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;
}
  • 控制样式的几个属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
1
2
3
4
// checkbox-group组件实例的value或当前value
store() {
return this._checkboxGroup ? this._checkboxGroup.value : this.value;
}
  • v-model对应的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 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事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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,与表单验证相关
1
2
3
4
5
6
watch: {
// 监听value变化,向上找到form组件则发布el.form.change事件暴露出value
value(value) {
this.dispatch('ElFormItem', 'el.form.change', value);
}
}
  • dispatch: 从mixins混入进来的方法,向上寻找(指定组件,发布指定事件,暴露指定值)
1
import Emitter from 'element-ui/src/mixins/emitter'

checkbox-button

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

------ 本文结束------
0%