Element组件研究-Checkbox多选框

微信扫一扫,分享到朋友圈

Element组件研究-Checkbox多选框

前言

相信量变引起质变,我们继续来研究Element的组件

以前的研究:

Element组件研究-Button

Element组件研究-Input输入框

Element组件研究-Layout,Link,Radio

还是老套路,先实现最简单的组件封装,再不断给其添加功能。

最基本的实现

区别于原生checkbox只有一个方形选择框,element的checkbox有内容区域。

<el-checkbox v-model="checked">内容区域</el-checkbox>
复制代码

且通过v-model来绑定是否选中。

下面贴出基本实现代码:

<template>
<label
class="el-checkbox"
:class="[
{ 'is-checked': isChecked }
]"
>
<span
:class="{
'is-checked': isChecked,
}"
>
<span></span>
<input
ref="checkbox"
class="el-checkbox__original"
type="checkbox"
:checked="isChecked"
@input="handleInput"
@change="handleChange"
>
</span>
<span v-if="$slots.default">
<slot></slot>
</span>
</label>
</template>
<script>
export default {
name: 'ElCheckbox',
props: {
value: {},
},
computed: {
isChecked() {
return this.value
}
},
methods: {
handleChange(ev) {
this.$emit('change', ev.target.checked, ev);
},
handleInput(ev) {
this.$emit('input', ev.target.checked, ev);
}
},
}
</script>
复制代码

之前我一直以为v-model就是:value和@input的结合体。原来在原生checkbox上,是:check和@input的结合体。所以上面也可以通过v-model实现对原生checkbox的绑定:

<!-- :checked="isChecked"
@input="$emit('input', $event.target.checked , ev)" -->
// 将上面的代码替换为v-model="model",model是一个计算属性
<input
ref="checkbox"
class="el-checkbox__original"
type="checkbox"
v-model="model"
@change="handleChange"
>
...
computed: {
model: {
get() {
return this.value
},
set(val) {
this.$emit('input', val);
}
},
isChecked() {
return this.model
}
},
复制代码

这样,我们的实现方式就贴近于源码的实现方式了。

禁用状态

先写测试代码

<el-checkbox v-model="checked" disabled>内容区域</el-checkbox>
复制代码

再为组件添加disabled,根据属性判断样式,给input标签添加:disabled=”disabled”即可。

效果如下:

多选框组

测试代码:

<el-checkbox-group v-model="checkList" @change="onChange">
<el-checkbox label="复选框 A"></el-checkbox>
<el-checkbox label="复选框 B"></el-checkbox>
<el-checkbox label="复选框 C"></el-checkbox>
<el-checkbox label="禁用" disabled></el-checkbox>
<el-checkbox label="选中且禁用" disabled></el-checkbox>
</el-checkbox-group>
复制代码

多选框组的工作方式和单个Checkbox有区别,值不是true/false了,而是绑定在group组件上的一个数组,选中的checkbox的label会被添加到此数组中。

写一个CheckboxGroup组件。实现思路和RadioGroup非常类似。

<template>
<div role="group">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'ElCheckboxGroup',
componentName: 'ElCheckboxGroup',
props: {
value: {},
disabled: Boolean,
},
};
</script>
复制代码

CheckboxGroup组件只是一个容器,主要的实现逻辑还在Checkbox组件中。

多选框组工作方式的不同,我们也可以猜到Checkbox组件中的逻辑实现也不一样。代码大体如下:

model: {
get() {
return this.isGroup() ? this.store : this.value
},
set(val) {
if (this.isGroup()) {
this.dispatch('ElCheckboxGroup', 'input', [val]);
} else {
this.$emit('input', val);
}
}
},
...
isGroup() {
let parent = this.$parent;
while (parent) {
if (parent.$options.componentName !== 'ElCheckboxGroup') {
parent = parent.$parent;
} else {
this._checkboxGroup = parent;
return true;
}
}
return false;
},
store() {
return this._checkboxGroup ? this._checkboxGroup.value : this.value;
},
复制代码

上面的代码实现了在CheckBox中操作父Group的:value的值。

通过isGroup方法判断是否在group中,如果在,就走另一套逻辑。这时候model的set方法的参数val不是true/false。而是checkList:[‘复选框 A’,’选中且禁用’]这样的数组了。绑定组件的value值彻底变化了。在原生组件上添加:value=”label”,这里面利用了一个知识点,当value有值时(label有值,也就是在group中),原生组件的v-model绑定的不再是checked属性,而是value属性了。

此时再判断当前CheckBox有没有被选中:

isChecked() {
if ({}.toString.call(this.model) === '[object Boolean]') {
return this.model;
} else if (Array.isArray(this.model)) {
// 重点是这句,如果model是数组,说明组件在group中,判断lable在不在group的value中
return this.model.indexOf(this.label) > -1;
}
return false;
},
复制代码

效果如下:

indeterminate 状态

indeterminate 属性用以表示 checkbox 的不确定状态,一般用于实现全选的效果。

测试代码如下:

<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
<div></div>
<el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
<el-checkbox v-for="city in cities" :label="city" :key="city">{{city}}</el-checkbox>
</el-checkbox-group>
const cityOptions = ['上海', '北京', '广州', '深圳'];
data() {
return {
checkAll: false,
checkedCities: ['上海', '北京'],
cities: cityOptions,
isIndeterminate: true
};
},
methods: {
handleCheckAllChange(val) {
this.checkedCities = val ? cityOptions : [];
this.isIndeterminate = false;
},
handleCheckedCitiesChange(value) {
let checkedCount = value.length;
this.checkAll = checkedCount === this.cities.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length;
}
},
复制代码

组件中添加indeterminate属性,控制样式即可,没有啥复杂度,效果如下:

可选项目数量的限制

  1. 组件添加isLimitExceeded:false

  2. 添加isLimitDisabled计算属性。根据group的max和min属性判断自己还能不能被选择。

isLimitDisabled() {
const { max, min } = this._checkboxGroup;
return !!(max || min) &&
(this.model.length >= max && !this.isChecked) ||
(this.model.length <= min && this.isChecked);
},
复制代码
  1. 最后在isDisabled计算属性中添加this.isLimitDisabled的禁用逻辑。

效果如下:

按钮样式

新写一个组件CheckboxButton,逻辑与Checkbox基本类似,不再赘述。详细代码可以下下面的码云仓库。

带有边框

给组件添加属性,增加样式判断。不再赘述。

效果如下:

总结

Checkbox组件的研究就到这里。代码在码云: gitee.com/DaBuChen/my…

特斯拉Model Y在6月份销售7500辆 是Model X两倍多

上一篇

v$logmnr_contents中特殊delete语句解惑

下一篇

你也可能喜欢

Element组件研究-Checkbox多选框

长按储存图像,分享给朋友