[vue] Solve the problem that the lazy loading data of the tree list in el-tree or el-table cannot be refreshed in real time and use

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 map
  • map.set(key, value)Add key-value pairs to the map
  • map.get(key)Get the value according to the key
  • map.delete(key)Delete specified data
  • map.has(key)Check if the specified key is contained in the map
  • map.clear()Delete all key-value pairs
  • map.keys()Get all the keys of the map
  • map.values()Get all the values ​​of the map
  • 4.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 loop

    The 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>
    
    

Guess you like

Origin blog.csdn.net/liqiannan8023/article/details/130728848