Article Directory
-
- 1. Problem description
- 2. Problem solving
-
- 1. First add a map to the data return to access data
- 2. In the method of loading children in the el-tree or tree list component, use map to save the parent node loaded each time
- 3. Encapsulate a refreshLoadTree method, which is called after each addition, deletion, modification and query operation, so as to achieve the purpose of real-time refresh
- 3. Rediscover the problem
1. Problem description
In the project, I encountered a problem that the tree structure of the el-table was not refreshed after modifying the data. It needs to be manually refreshed before it can be refreshed.
2. Problem solving
1. First add a map to the data return to access data
data() {
return {
maps: new Map()
}
}
Knowledge supplement:
Map object:
1.Map is used to store key-value pairs of data. It differs from Object in that:
- The property name in Object can only be a string or a symbol . If a property name of another type is passed, the JS interpreter will automatically convert it to a string
- Any type of value in the Map can be the key of the data
- 2. Create a Map object
const map = new Map() map.set("key", "value") map.delete(key) console.log(map.get("key")) //value console.log(map.has("key")) //ture or false
3. Introduction to common methods
map.size()
Get the number of key-value pairs in the mapmap.set(key, value)
Add key-value pairs to the mapmap.get(key)
Get the value according to the keymap.delete(key)
Delete specified datamap.has(key)
Check if the specified key is contained in the mapmap.clear()
Delete all key-value pairsmap.keys()
Get all the keys of the mapmap.values()
Get all the values of the map4.Map to array
// 方法一: const arr = Array.from(map) // [["name","孙悟空"],["age",18]] // 方法二: const arr = [...map]
References are drawn from: Introduction to Map objects and common methods
2. In the method of loading children in the el-tree or tree list component, use map to save the parent node loaded each time
async loadChildren(tree,treeNode,rsolve){ this.maps.set(tree.id,{ tree,treeNode,resolve}) //储存数据 // 调用接口,回显树型内容 const resp = await this.getChildren(tree.id) resolve(resp.data) }
3. Encapsulate a refreshLoadTree method, which is called after each addition, deletion, modification and query operation, so as to achieve the purpose of real-time refresh
refreshLoadTree(lazyTreeNodeMap, maps, parentId) { if (maps.get(parentId)) { const { tree, treeNode, resolve } = maps.get(parentId) this.$set(lazyTreeNodeMap, parentId, []) if (tree) { // 重新执行父节点加载子级操作 this.loadChildren(tree, treeNode, resolve) if (tree.parentId) { // 若存在爷爷结点,则执行爷爷节点加载子级操作,防止最后一个子节点被删除后父节点不显示删除按钮 const a = maps.get(tree.parentId) this.loadChildren(a.tree, a.treeNode, a.resolve) } } } }
The three parameters passed in are: the node where the component lazily loads data, the stored maps data, and the parent node of the operated node
use
this.refreshLoadTree(this.$refs.table.store.states.lazyTreeNodeMap, this.maps, this.temp.parentId)
components
<el-table ref="table"></el-table>
principle
First, take out the data of the child node that has just passed through the shelf from the map, and then use this.$set to clear the data corresponding to the parent node, so as to realize the real-time refresh of the view, and then reload the parent node through the taken out data
Refer to the above content: Solve the problem that el-tree or tree list lazy loading data cannot be refreshed in real time after changing
3. Rediscover the problem
3.1 Problem Description
When using the el-table form to lazy load child data, lazy loading will only be loaded when it is expanded for the first time, and the data cached for the first time will be used later without reloading.
3.2 Problem Solving
<el-table :data="tableData1" style="width: 100%" row-key="id" border lazy :load="load" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" @expand-change="hanleExpandChange"> <!-- 内容省略 --> </el-table>
field description
row-key: Required when rendering tree structure data
lazy: Load function load when the attribute is true
@expand-change: This event will be triggered when the user expands or closes a row, (callback when the row is expanded The second parameter is expandedRows; the second parameter is expanded in tree form)1. Content in the load method
async load(tree,treeNode,resolve){ // 在声明的全局变量中,增加一个key为本条数据的id,id可替换为数据中的任意值 this.tableTreeRefreshTool[tree.id] = { } // 重要!保存resolve方法,以便后续使用 this.tableTreeRefreshTool[tree.id].resolve = resolve // 记录展开次数,具体作用后续介绍 this.tableTreeRefreshTool[tree.id].expandCount = 0 // 调用接口 const resp = await this.getChildren(tree.id) resolve(resp.data) }
2. Set the expand-change event
async hanleExpandChange(row,expanded){ // 获取到之前保存的全局变量 const curr = this.tableTreeRefreshTool[row.id] // 展开次数+1 curr.expandCount++ // 如果是展开状态,且展开次数大于1,且上一次的状态为折叠,则请求api数据更新子菜单 if (expanded && curr.expandCount > 1 && !curr.prevStatus) { // api请求 const resp = await this.getChildren(tree.id) curr.resolve(resp.data) } // 保存本次的展开或折叠状态,用于下次判断 curr.prevStatus = expanded }
data interpretation
expandCount represents the number of expansions. This is to prevent the first expansion from being loaded by lozyload. Repeated loading here will cause conflicts. The
use of prevStatus is because the expand-change method will be triggered again after the resolve method is called. If no judgment is made , will lead to an infinite loopThe above content refers to: ElementUI el-table tree form lazy loading How to manually refresh the el-table tree form Manual refresh method
So far, the bug modification related to load has been completed, and the complete code is as follows
<template> <el-table :data="tableData1" style="width: 100%" row-key="id" border lazy :load="load" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" @expand-change="hanleExpandChange"> <!-- 内容省略 --> </el-table> </template> <script> export default { data(){ return { mapstableTree: new Map(), tableTreeRefreshTool: { }, } }, methods:{ load(tree, treeNode, resolve){ //增删改的时候存储数据 this.mapstableTree.set(tree.id, { tree, treeNode, resolve }) // 在之前声明的全局变量中,增加一个key为 本条数据的id,id可替换为你数据中的任意唯一值 this.tableTreeRefreshTool[tree.id] = { } // 重要!保存resolve方法,以便后续使用 this.tableTreeRefreshTool[tree.id].resolve = resolve // 记录展开次数,具体作用后续介绍 this.tableTreeRefreshTool[tree.id].expandCount = 0 getAxios(tree.id).then(res => { resolve(res.data.erpOrderProductList) }) }, //封装一个增删改刷新table数据的方法,组件懒加载数据的节点,data return的maps,及被操作节点的父节点 refreshLoadTree (lazyTreeNodeMap, maps, parentId) { console.log("单个刷新的tree", lazyTreeNodeMap, maps, parentId); if (maps.get(parentId)) { const { tree, treeNode, resolve } = maps.get(parentId) this.$set(lazyTreeNodeMap, parentId, []) if (tree) { // 重新执行父节点加载子级操作 this.loadTreeChild(tree, treeNode, resolve) if (tree.parentId) { // 若存在爷爷结点,则执行爷爷节点加载子级操作,防止最后一个子节点被删除后父节点不显示删除按钮 const a = maps.get(tree.parentId) this.loadTreeChild(a.tree, a.treeNode, a.resolve) } } } }, handleExpandChange (row, expanded) { const curr = this.tableTreeRefreshTool[row.id] // this.refreshLoadTree(this.$refs.table.store.states.lazyTreeNodeMap, this.mapstableTree, this.form.productId) curr.expandCount++ // 如果是展开状态,且展开次数大于1,且上一次的状态为折叠,则请求api数据,更新子菜单 if (expanded && curr.expandCount > 1 && !curr.prevStatus) { getAxios(row.id).then(res => { curr.resolve(res.data.shopProductVariantList) }) } // 保存本次的展开或折叠状态,用于下次判断 curr.prevStatus = expanded }, // 提交修改按钮 submitForm(){ this.$refs["form"].validate(valid => { if (valid) { this.$refs['tableform'].validate(table => { if (table) { if (this.form.id != null) { updateErpOrder(this.form).then(response => { this.$modal.msgSuccess("修改成功"); this.open = false; this.getList(); // 调用刷新展开的table this.refreshLoadTree(this.$refs.table.store.states.lazyTreeNodeMap, this.mapstableTree, this.form.id) }); } else { addErpOrder(this.form).then(response => { this.$modal.msgSuccess("新增成功"); this.open = false; this.getList(); }); } } }) } }); } } } </script>