preface
Hello, everyone! I am a DongXH,
Today, I would like to share a vue-tree-Selet component package with you. During the development process, we may encounter a new business requirement, or we may encounter an existing function to iterate on new functions.
The tree-select component is a modified iteration of the original business requirements, based on el-drawer nested El-tree and el-select drop-down selection.
It’s worth thinking about iterating on an existing feature.
Not just command+ C and command+ V!
This article summarizes some of the problems encountered in component encapsulation and the solutions, as well as my own idea of a component encapsulation.
Writing summary is not easy, if there is a better design and thought, look forward to collision, we make progress together.
Demand analysis
The general requirements are as follows:When I got the requirements draft, I looked at it firstelement-ui
theel-tree
A single component is unable to meet the requirements, so the need for secondary development of components, combinedel-select
andel-dialog
Implement requirements.
Among them, several processes are carried out:
- If all the children of the parent are checked, then by default only one ID of the parent is returned to the background. Otherwise, check all subsets in our
tree
There will be 1W + nodes in the message, and all postbacks are extremely unfriendly to interface performance. - If all child nodes under the parent are unselected, all selected subsets are sent back.
- Select the node, click to load subset data, reduce the component’s first rendering data.
Next, I thought about the functions to be implemented according to the requirements as follows:
- Support one-time and lazy data loading.
- Users can click to select by expanding categories. (PS: Click on the first panel to expand the first panel of its child nodes)
- Initialization state is supported. The first parent node will be expanded by default or the output value is worth expanding.
- Support for strict adherence to father-child disconnection.
- Single and multiple options are supported.
- Support select select box width custom, dialog width and height custom.
Component specific usage
After components are imported into the current page, the detailed Settings are as follows:
<select-tree
v-model="Bound Model name"
:width="100% ` `"
:height="`auto`"
:maxHeight="`400px`"
:nodeKey="'department_id'"
size=""
multiple
clearable
:defaultProps="{ children: 'children', label: 'short_name' }"
:defaultExpandedKeys="Default expanded array of nodes"
:checkedKeys="Array of nodes selected by default"
@change="changeTreeItem"
:getGroupSequence="getGroupSequence"
/>
Copy the code
The specific implementation
The first step is to determine which fields the component needs to pass in from the parent.
props: {
// Get the tree-data interface
getGroupSequence: {
type: Function.default(){}},// props custom configuration
defaultProps: {
type: Object.default() {
return{}; }},// Whether the configuration can be multiple
multiple: {
type: Boolean.default() {
return false; }},clear: {
type: Boolean.default() {
return false; }},// el-select configures whether the selection can be cleared
clearable: {
type: Boolean.default() {
return false; }},// Whether to display the selected value as a text when configuring multiple selection
collapseTags: {
type: Boolean.default() {
return false; }},// Set the nodeKey value of el-tree
nodeKey: {
type: String.default() {
return "department_id"; }},// Displays the checkbox case whether to strictly follow the parent-child association
checkStrictly: {
type: Boolean.default() {
return false; }},// The default selected node key array
checkedKeys: {
type: Array.default() {
return[]; }},// The size style of el-select
size: {
type: String.default() {
return "medium"; }},// The size style of el-select
width: {
type: String.default() {
return `250px`; }},// The default height of the el-Dialog
height: {
type: String.default() {
return `300px`; }},// A collection of tree nodes expanded by default
defaultExpandedKeys: {
type: Array.default() {
return ["D1000001"]; }},// The default height of the el-Dialog. If the height is set to 100%, the maximum height will be set
maxHeight: {
type: String.default() {
return `400px`; }},// Whether node data is loaded lazily
lazy: {type: Boolean.default() {
return true; }}},Copy the code
If the default is new and no defaultExpandedKeys are passed in, the default component renders a list of levels:
getTreeData(cb) {
this.getGroupSequence({ department_id: "Level 1 Component ID" }).then(res= > {
this.treeData = res.data;
cb();
});
},
Copy the code
In Mounted execute render data function:
mounted() {
this.getTreeData(() = > {
this.initCheckedData();
});
},
Copy the code
There needs to be a callback function to perform the default height of el-Dialog before the callback function is executed:
initCheckedData() {
if (this.multiple) {
/ / multi-select
this.defaultExpand = this.defaultExpandedKeys;
this.selectedData = this.checkedKeys;
this.options = this.checkedKeys;
this.checkedKeys.map(item= > {
if (item) {
this.defaultDeptAll.push(item.department_id); }}); }else {
/ / radio
if (this.selectedData.length > 0) {
this.checkSelectedNode(this.selectedData); }}this.$nextTick(() = > {
this.popoverWidth = this.$refs.select.$el.clientWidth - 24;
});
},
Copy the code
Load =”loadNode”;
loadNode(node, resolve) {
if (node.level === 0) {
return;
}
this.getGroupSequence({ department_id: node.data.department_id }).then(
res= > {
if (res.data && res.data.length > 0) {
resolve(res.data);
this.$refs.tree.setCheckedKeys(this.defaultDeptAll);
} else{ resolve([]); }}); }Copy the code
Set to click the node according to the current parent node ID to obtain the subset, rendering. Then it is the judgment processing of the selection based on the single and multiple values passed in:
// Select the callback when the node is clicked, and return the data of the clicked node
handleNodeClick(data, node) {
if (!this.multiple) {
this.setSelectOption(node);
this.isShowSelect = !this.isShowSelect;
this.$emit("change".this.selectedData); }},// Multiple options, callback when the node status changes
handleCheckChange(data, checked, node) {
console.log("handleCheckChange", data, checked, node);
if (checked) {
let array = this.$refs.tree.getNode(data.department_id);
if (array.childNodes.length == 0) {
this.checkedData.push(data);
this.defaultDeptAll.push(data.department_id); }}else {
if (this.checkedData.length > 0) {
this.checkedData.forEach((item, index) = > {
if (item.department_id == data.department_id) {
this.defaultDeptAll.splice(index, 1);
this.checkedData.splice(index, 1); }}); }}if (this.firstLoad || this.checkedKeys.length == 0) {
this.setCheckedKey();
} else {
this.firstLoad = true;
}
this.$emit("change".this.defaultDeptAll, this.defaultExpand);
},
Copy the code
< span style = “box-sizing: inherit! Important; word-break: inherit! Important;”
// Delete the callback for any select option
removeSelectedNodes(val) {
this.$refs.tree.setChecked(val, false);
var node = this.$refs.tree.getNode(val);
if (!this.checkStrictly && node.childNodes.length > 0) {
this.treeToList(node).map(item= > {
if (item.childNodes.length <= 0) {
this.$refs.tree.setChecked(item, false); }}); }this.$emit("change".this.selectedData);
}
Copy the code
There are some other common functions of the function is not a list, the specific code please jump to see;
Component source code address
Git address – vue – tree – select
analyse
Fulfilling business requirements is not difficult, and there can be many ways to do it. I think it’s more about thinking through the development process and how you design that’s an important part of writing code at the beginning. The overall component design affects a lot, and a good design idea will make your code more reusable, extensible, and component performance.
There were a lot of problems during the development process, some of which stuck for a long time, such as re-rendering when a default value was reflected, reassigning the content exposed by a child component to a parent component caused the component to loop. Encounter problems, solve problems, reflect on the problem, to their own technical improvement has a great help ~
Currently, the component has been put into use, but there are still the following problems, which need to be further optimized in the later stage:
- Our requirement is to return the parent ID if all subsets are checked, but if there is only one subset under the current parent, will the result return the current subset or the parent node?
el-tree
The current version has no search function.- Other unreasonable places for optimization iteration.
conclusion
In the process of development, I still think it is necessary to package components to design components, development ideas and development ability are equally important, clear thinking, get twice the result with half the effort.
This article is a recent project online, if you feel helpful, welcome to like, star~~
If you have a better idea or a way to do it, feel free to leave a comment in the comments section