preface
The research idea of this paper is to read Element source code, and then automatically write components step by step to improve their corresponding functions.
Believing that quantitative change causes qualitative change, we continue our study of Element’s components.
Previous studies:
Element component source research -Button
Element component source research -Input Input box
Element component source research -Layout, Link, Radio
It’s the same old approach: encapsulate the simplest components first and then add functionality to them.
The most basic implementation
Unlike a native Checkbox, which has a square checkbox, Element’s Checkbox has a content area.
<el-checkbox V-model ="checked"> Content area </el-checkbox>Copy the code
And whether it is selected is bound by v-model.
The basic implementation code is posted below:
<template>
<label
class="el-checkbox"
:class="[
{ 'is-checked': isChecked }
]"
>
<span class="el-checkbox__input"
:class="{
'is-checked': isChecked,
}"
>
<span class="el-checkbox__inner"></span>
<input
ref="checkbox"
class="el-checkbox__original"
type="checkbox"
:checked="isChecked"
@input="handleInput"
@change="handleChange"
>
</span>
<span class="el-checkbox__label" 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>
Copy the code
I used to think of v-Model as a combination of :value and @input. Check (@input); check (@input); We can also bind the native checkbox with the V-model:
<! -- :checked="isChecked" @input="$emit('input', $event.target. Checked, ev)" --> <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 } },Copy the code
In this way, our implementation is close to the implementation of the source code.
Disabled state
Write the test code first
<el-checkbox V-model ="checked" disabled> Content area </el-checkbox>Copy the code
Add disabled to the component, depending on the style of the attribute, and add :disabled=”disabled” to the input tag.
The effect is as follows:
Checkboxes group
Test code:
<el-checkbox-group V-model ="checkList" @change="onChange"> <el-checkbox label=" Checkbox A"></el-checkbox> <el-checkbox Label =" Checkbox B"></el-checkbox> < el-Checkbox Label =" checkbox C"></ el-Checkbox >< el-Checkbox label=" disabled "disabled></ el-Checkbox > <el-checkbox label=" Select and disable "disabled></el-checkbox> </el-checkbox-group>Copy the code
A Checkbox group works differently from a single Checkbox. Instead of being true/false, it is an array bound to the group component, to which the selected Checkbox’s label is appended.
Write a CheckboxGroup component. The implementation idea is very similar to RadioGroup.
<template> <div class="el-checkbox-group" role="group"> <slot></slot> </div> </template> <script> export default { name: 'ElCheckboxGroup', componentName: 'ElCheckboxGroup', props: { value: {}, disabled: Boolean, }, }; </script>Copy the code
The CheckboxGroup component is just a container, and the main implementation logic is still in the Checkbox component.
Depending on how Checkbox groups work, we can also guess that the logic in the Checkbox component is implemented differently. The code looks like this:
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; },Copy the code
The code above implements the operation on the parent Group’s :value value in the CheckBox.
The isGroup method is used to determine whether it is in the group. If so, a different set of logic is used. Val is not true/false. Rather, an array such as checkList:[‘ checkbox A’,’ selected and disabled ‘]. The value of the bound component has changed completely. Add value=”label” to the native component. When value has a value (label has a value, that is, in the group), the native component’s V-model will no longer bind checked attributes, but value attributes.
Check whether the current CheckBox is checked:
isChecked() { if ({}.toString.call(this.model) === '[object Boolean]') { return this.model; } else if (array.isarray (this.model)) {} else if (array.isarray (this.model)) { Return this.model.indexof (this.label) > -1; } return false; },Copy the code
The effect is as follows:
Indeterminate state
The indeterminate attribute is used to indicate the indeterminate state of the checkbox, and is generally used to achieve the effect of selecting all.
The test code is as follows:
<el-checkbox :indeterminate="isIndeterminate" V-model ="checkAll" @change="handleCheckAllChange"> All </el-checkbox> <div style="margin: 15px 0;" ></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> const cityOptions = [' Shanghai ', 'Beijing ',' Guangzhou ', 'shenzhen']; Data () {return {checkAll: false, checkedCities: [' Shanghai ', 'Beijing '], 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; }},Copy the code
Add the indeterminate attribute to the component, control the style, no complexity, effect is as follows:
Limits on the number of items available
-
Component Add isLimitExceeded:false
-
Add the isLimitDisabled calculation attribute. Determine whether a group can be selected based on its Max and min attributes.
isLimitDisabled() { const { max, min } = this._checkboxGroup; return !! (max || min) && (this.model.length >= max && ! this.isChecked) || (this.model.length <= min && this.isChecked); },Copy the code
- Finally, add the disablement logic for this.isLimitDisabled to the isDisabled calculation property.
The effect is as follows:
Button style
Create a new component called CheckboxButton. Detailed code can be found in the code cloud repository below.
With a frame
Add attributes to components to increase style determination. No further elaboration.
The effect is as follows:
conclusion
So much for the Checkbox component. Code in the code cloud: gitee.com/DaBuChen/my…
Other component source code study:
Element component source research -Button
Element component source research -Input Input box
Element component source research -Layout, Link, Radio
Element component source research -Checkbox multi-checkbox
Element component source research -InputNumber counter
Element component source code study -Loading component
Element component source research -Message component