First look at the renderings:
Github project address: address.
First, if you want to understand the overall structure of the Cascader component, you can read this article first.
The process of modifying the entire cascader component is as follows:
- Add a full selection button to see first on the page.
- Add click logic for all buttons.
- Update the status of all buttons according to the check status of cascader-Node collection.
Step 1: Add all buttons
The Cascader-Node component is rendered in the Cascader-Menu component with the following rendering code:
renderNodeList(h) { const { menuId} = this; const { isHoverMenu } = this.panel; const events = { on: {} }; if (isHoverMenu) { events.on.expand = this.handleExpand; } // This is the cascader-node set to render const nodes = this.nodes. Map ((node, index) => {const {hasChildren} = node; return ( <cascader-node key={ node.uid } node={ node } node-id={ `${menuId}-${index}` } aria-haspopup={ hasChildren } aria-owns = { hasChildren ? menuId : null } { ... events }></cascader-node> ); }); // Render the Cascader-Node collection, we just need to insert all the selected components here. return [ ...nodes, isHoverMenu ? <svg ref='hoverZone' class='el-cascader-menu__hover-zone'></svg> : null ]; }Copy the code
The code after adding the select all button looks like this:
return [ config.checkAll && index === 0 && <el-checkbox class="checkAll" indeterminate={isIndeterminate} Value ={checkAll} onChange={handleCheckAllChange}> All </el-checkbox>,...nodes, isHoverMenu ? <svg ref='hoverZone' class='el-cascader-menu__hover-zone'></svg> : null ];Copy the code
Config. checkAll is the props parameter passed to the Cascader component.
For example, if I want to enable the checkAll function, I pass in the checkAll: true parameter.
<el-cascader
:options="options"
:props="props"
collapse-tags
clearable></el-cascader>
data() {
return {
props: { multiple: true, checkAll: true, expandTrigger: 'hover' },
}
}
Copy the code
That all selected item is going to be rendered.
Step 2: Add click logic for all buttons
Check the logical address of the el-checkbox.
Take a look at the cascader-Menu rendering block again:
return [ config.checkAll && index === 0 && <el-checkbox class="checkAll" indeterminate={isIndeterminate} Value ={checkAll} onChange={handleCheckAllChange}> All </el-checkbox>,...nodes, isHoverMenu ? <svg ref='hoverZone' class='el-cascader-menu__hover-zone'></svg> : null ];Copy the code
We added two properties and a method to the el-Checkbox component:
- Value: true-> All, false-> To be determined.
- Indeterminate: When value is true, this attribute is invalid. If value is false, the property is not selected; if true, the property is not selected.
- OnChange: Triggered when the button is clicked.
Take a look at the onChange trigger function first, take a closer look at the code comment:
handleCheckAllChange() { const { nodes, panel } = this; // Reverse the state of the all-select button this.checkAll =! this.checkAll; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; // Trigger the doCheck method for all cascader-Node components in the current cascader-menu group. The effect and logic behind it is the same as clicking cascader-Node. node.doCheck(this.checkAll, true); } // Trigger the cascader-panel method, which updates the checkValue. panel.calculateMultiCheckedValue(); },Copy the code
We write a method updateInDeterminate in the Cascader-Menu component that updates the status of the all button based on the check status of the Cascader-Node collection.
updateInDeterminate() {
const { panel, nodes } = this;
if (panel.config.checkAll) {
let counter = 0;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
(node.checked || node.indeterminate) && counter++;
}
this.checkAll = counter === nodes.length;
this.isIndeterminate = !(counter === nodes.length || counter === 0);
}
},
Copy the code
When the updateInDeterminate method fires:
1, cascader-menu creation
created() { if (this.panel.config.checkAll && this.index === 0) { this.updateInDeterminate(); this.$on('updateInDeterminate', this.updateInDeterminate); }},Copy the code
2. When the node parameters passed in cascader-menu change
watch: { nodes() { this.panel.config.checkAll && this.index === 0 && this.updateInDeterminate(); }}Copy the code
3, Cascader-panel component checkValue (this refers to the cascader selected value) changes
watch: { checkedValue(val) { if (! isEqual(val, this.value)) { this.checkStrictly && this.calculateCheckedNodePaths(); Broadcast ('ElCascaderMenu', 'updateInDeterminate'); // This. Broadcast ('ElCascaderMenu', 'updateInDeterminate'); this.$emit('input', val); this.$emit('change', val); }}}Copy the code
4. Delete the cascader component tag
deleteTag(tag) { const { checkedValue, panel } = this; const current = tag.node.getValueByOption(); const val = checkedValue.find(n => isEqual(n, current)); this.checkedValue = checkedValue.filter(n => ! isEqual(n, current)); // If select all is enabled, then delete tag, If (this.config.checkAll) {this.$nextTick(() => {panel.$refs.menu.forEach((menu) => {panel. menu.updateInDeterminate(); }); }); } this.$emit('remove-tag', val); },Copy the code