vue的element ui使用el-table组件实现懒加载树、默认自动展开层级(一层,二层)、并且解决新增、删除、修改之后树节点不刷新问题

news2024/11/18 17:28:09

1.整体思路

  1. 问题:数据量太大了,导致接口返回数据时间较长。
  2. 解决: 将ElementUi中Table组件加载改为懒加载(查看文档)。
  3. 思路:初始化打开页面时只显示第一级菜单,用户点击展开菜单之后往后端发送请求,然后加载出一级子菜单;后台只用有一个根据菜单id查询他子菜单的接口就可以。
  4. 拓展问题对table树增删改查后,会存在table菜单节点不刷新问题,实际数据已经刷新。( 改成懒加载后, 加载很快.;但是子菜单加载一次之后就被缓存了,在怎么点击也不会重新去请求后台;这个也导致了在我们增删改排序等操作菜单之后, 页面对应的菜单节点没有更新, 实际数据已变更.; 整体刷新一下页面的话会显示正确, 不过不可能每次更新之后,强制刷新页面吧,这样交互效果很不好)。
    5.解决不刷新问题:刷新节点(修改了哪一行, 就拿到这一行数据的parentId, 然后去调用接口, 查到这个parentId下一级子菜单,查到数据之后塞回去就行了. 接口和页面加载的那个接口是复用的, 无非页面加载的时候parentId传的是0或者null)。
    6.关键
    this.$set(this.$refs.pointMultipleTable.store.states.lazyTreeNodeMap, key, data)
    
    // lazyTreeNodeMap: 就是this.$refs.table.store.states.lazyTreeNodeMap
    
    //  key:就是table-key,相当于父节点数据的id
    
    // data:就是子节点数据
    
    // this.$refs.pointMultipleTable注意这个pointMultipleTable是你的table属性:ref的名字
    //	步骤 :
         // 1、先给table标签添加一个ref="pointMultipleTable",ref可以自己随便自定义
        // 2、在点击父节点要添加一个子节点,或删除一个子节点后,已请求完后台接口后,拿到父节点id,和最新增删后的子节点数据xxxList
        // 3、最后调用 this.$set(this.$refs.table1.store.states.lazyTreeNodeMap, id, xxxList);//根据父节点id更新子节点数据
    

2. 代码实现

<template>
    <div class="app-container">
        <el-table ref="pointMultipleTable" v-loading="loading" :data="deptList" row-key="deptId" :lazy="true" :load="load"
            :tree-props="{ children: 'children', hasChildren: 'existSub' }" :expand-row-keys="expandRowKeys"
            @row-click="(row, column, e) => clickRowLoad(row, column, e)">
            <el-table-column prop="deptName" label="部门名称" min-width="260" />
            <el-table-column prop="orderNum" label="排序" />
            <el-table-column label="创建时间" align="center" prop="createTime" min-width="200">
                <template slot-scope="scope">
                    <span>{{(scope.row.createTime)}}</span>
                </template>
            </el-table-column>
            <el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="200">
                <template slot-scope="scope">
                    <el-button  size="mini" type="text" icon="el-icon-edit"
                        @click.stop="handleUpdate(scope.row)">修改</el-button>
                    <el-button  size="mini" type="text" icon="el-icon-plus"
                        @click.stop="handleAdd(scope.row)">
                        新增</el-button>
                    <el-button  size="mini" type="text" icon="el-icon-delete"
                        @click.stop="handleDelete(scope.row)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>
  
<script>
import {
    getDept,
    delDept,
    addDept,
    updateDept,
    lazyList
} from '@/api/manager/dept'

// 设置循环的默认值,判断是否调用openTreeHandle,触发点击事件,使得节点展开
let index = 1
export default {
    name: 'deptTree',
    components: {
    },
    data() {
        return {
            expandRowKeys: [],
            parentId: '',
            type: '',
            // treeNodeMap: new Map(),
            // 遮罩层
            loading: true,
            // 表格树数据
            deptList: [],
            // 查询参数
            queryParams: {
                parentId: undefined
            }
        }
    },
    created() {
        // 部门列表
        this.getList()
    },
    methods: {

        /** 查询部门列表 懒加载 */
        getList() {
            this.loading = true
            lazyList(this.queryParams).then(response => {
                console.log(response, 'response查询部门列表')
                this.deptList = response.data
                this.loading = false
                // 默认展开了deptList的第一层所有数据的下级数据(相当于自动点击了一次)
                this.openTreeHandle(this.deptList)
            })
        },
        // 点击列表懒加载
        load(tree, treeNode, resolve) {
            console.log(tree, 'tree')
            // 加载子节点时,对子节点进行赋值
            // this.treeNodeMap.set(tree.deptId, { tree, treeNode, resolve })

            this.queryParams.parentId = tree.deptId
            lazyList(this.queryParams).then(res => {
                console.log(res.data, 'res.data')
                // deptList的第一层展开后,如果还想展开下面层级,就设置index且调用if的方法。
                // index <= 1 就表示第一层基础上再展开一层,index <= 2,表示第一层的基础上再展开2层,一次类推
                // 如果只要默认展开一层,则不要再调用openTreeHandle方法即可。注释掉下面的if的index相关。
                if (index <= 1) {
                    this.openTreeHandle(res.data)
                }
                index++
                resolve(res.data)
            })
        },
        // 一、-------根据接口得到deptList,根据实际需要获取需要展开的节点的id,也就是table绑定的row-key属性值(如deptId)--------
        openTreeHandle(deptList) {
            const deptId = deptList ? deptList.map(item => (item.deptId).toString()) : []
            // expandRowKeys 可以通过该属性设置 Table 目前的展开行,需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组
            // 这个必须配置,只有配置了这个,getElementsByClassName才能获取到对应的数据els,下面click事件才会触发
            this.expandRowKeys = this.expandRowKeys.concat(deptId)
            console.log(this.expandRowKeys, ' this.expandRowKeys')
            const els = document.getElementsByClassName('el-table__expand-icon el-table__expand-icon--expanded')
            this.$nextTick(() => {
                console.log(els, 'els')
                console.log(els.length, 'els.length')
                if (els.length > 0) {
                    for (let i = 0; i < els.length; i++) {
                        els[i].click()
                    }
                }
            })
        },

        // 点击整行load (能够点击一行的任意位置都可以进行伸缩)
        clickRowLoad(r, c, e) {
            if (e.currentTarget && e.currentTarget.firstElementChild.firstElementChild.firstElementChild) {
                console.log(e.currentTarget, 'e.currentTarget')
                if (e.currentTarget.firstElementChild.firstElementChild.firstElementChild.tagName == 'DIV') {
                    e.currentTarget.firstElementChild.firstElementChild.firstElementChild.click()
                } else {
                    e.currentTarget.firstElementChild.firstElementChild.firstElementChild.nextElementSibling.click()
                }
            }
        },

        /** 新增按钮操作(获取到当前的deptId作为parentId) */
        handleAdd(row) {
            console.log('新增按钮操作', row)
            // 获取对应的父级id
            this.parentId = row.deptId
            this.type = 1
          //  .....................
        },
        /** 修改按钮操作(获取当前部门的父级的id,也就是parentId) */
        handleUpdate(row) {
            console.log('修改部门增', row)
            // 根据部门id 获取详情
            getDept(row.deptId).then(response => {
                console.log(response.data, 'response.data')
                // 最近的父级id
                this.parentId = response.data.parentId
                this.type = 2
                 //  .....................
            })
        },

        /** 提交按钮 */
        submitForm: function () {
            this.$refs['form'].validate(valid => {
                if (valid) {
                    updateDept(this.form).then(response => {
                        this.$modal.msgSuccess('修改成功')
                        this.queryParams.parentId = null
                        // 方式1:刷新table
                        this.reflushtable()
                        // 方式2、刷新table
                        // this.refreshData()
                         //  .....................
                    })
                } else {
                    addDept(this.form).then(response => {
                        this.$modal.msgSuccess('新增成功')
                        this.queryParams.parentId = null
                        // 方式1:刷新table
                        this.reflushtable()
                        // 方式2、刷新table
                        // this.refreshData()
                         //  .....................
                    })
                }
            })
        },

        // 刷新节点:方法1
        reflushtable() { // 解决菜单懒加载时.  更新,添加,删除 排序不更新的情况 (根据父级id获取子级数据)
            lazyList({
                parentId: this.parentId
            }).then(res => {
                console.log(res.data, 'res.data')
                this.$set(this.$refs.pointMultipleTable.store.states.lazyTreeNodeMap, this.parentId, res.data)
                // 展开父级节点
                if (this.type == 1) { // 新增
                    const pid = this.parentId.toString()
                    this.expandRowKeys = this.expandRowKeys.concat([pid])
                    console.log(this.expandRowKeys, ' this.expandRowKeys-----')
                }
            })
        },

        // 如果对应节点没有展开过,那获取节点时候会出现获取不到情况(这个我暂时没有找到解决办法),
        //  this.treeNodeMap.get(this.parentId)找不到,在load中这个parentId没有存储过,故而获取不到。
        // 所以推荐使用上述方法1
        // 刷新节点:方法2
        refreshData() { 
            // 获取节点
            const node = this.treeNodeMap.get(this.parentId)
            // 获取需要刷新节点
            const { tree, treeNode, resolve } = node
            // 重新加载子节点数据
            this.load(tree, treeNode, resolve)
        },

        /** 删除按钮操作 */
        handleDelete(row) {
            this.$confirm('是否确认删除数据项?', '警告', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            })
                .then(function () {
                    return delDept(row.deptId)
                })
                .then(() => {
                    this.queryParams.parentId = null
                    this.$modal.msgSuccess('删除成功')
                    // 方式1:刷新table
                    this.reflushtable()
                    // 方式2、刷新table
                    // this.refreshData()
                     //  .....................
                })
                .catch(() => { })
        }

    }
}
</script>
  
  
  

3. 效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1384862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

13 | 使用代理ip爬取安居客房源信息

这是一个简单的Python爬虫代码,用于从安居客网站爬取房地产信息。该爬虫使用了代理IP来绕过可能的封禁,并提供了一些基本的信息抽取功能。 如果访问过多,那么可能出现了验证码 对此,最好的方法就是换ip。 使用代理IP的主要目的是保护爬虫的稳定性和隐私。以下是一些常见的原…

使用docker搭建LNMP架构

目录 环境准备 下载安装包 服务器环境 任务分析 nginx部分 建立工作目录 编写 Dockerfile 脚本 准备 nginx.conf 配置文件 生成镜像 创建自定义网络 启动镜像容器 验证nginx MySQL部分 建立工作目录 编写 Dockerfile 准备 my.cnf 配置文件 生成镜像 启动镜像…

优先级队列(Priority Queue)

文章目录 优先级队列&#xff08;Priority Queue&#xff09;实现方式基于数组实现基于堆实现方法实现offer(E value)poll()peek()isEmpty()isFull() 优先级队列的实现细节 优先级队列&#xff08;Priority Queue&#xff09; 优先级队列是一种特殊的队列&#xff0c;其中的元素…

基础命令继续

1&#xff1a;创建目录命令 mkdir命令 注意&#xff1a;创建文件夹需要修改权限&#xff0c;请确保操作均在HOME目录内&#xff0c;不要在Home外操作&#xff0c;涉及到权限问题&#xff0c;HOME外无法识别 小结&#xff1a; 练习: 2&#xff1a;touch创建文件 2&#xff1a;c…

统计学-R语言-4.5

文章目录 前言多变量数据多维列联表复式条形图并列箱线图R语言中取整运算主要包括以下五种&#xff1a; 点带图多变量散点图重叠散点图矩阵式散点图 练习 前言 本篇文章将继续对数据的类型做介绍&#xff0c;本片也是最后一个介绍数据的。 多变量数据 掌握描述多变量数据的分…

pytorch集智4-情绪分类器

1 目标 从中文文本中识别出句子里的情绪。和上一章节单车预测回归问题相比&#xff0c;这个问题是分类问题&#xff0c;不是回归问题 2 神经网络分类器 2.1 如何用神经网络分类 第二章节用torch.nn.Sequantial做的回归预测器&#xff0c;输出神经元只有一个。分类器和其区别…

安装nodejs出现问题

Error: EPERM: operation not permitted, mkdir… 全局安装express模块进行测试时&#xff1a; npm install express -g出现&#xff1a; 表示nodejs的安装目录无权限&#xff0c;根据错误日志的信息&#xff0c;定位到安装目录下&#xff1a; 点击属性&#xff1a; 点击编…

【江科大STM32合集】day2按键控制LED光敏传感器控制峰鸣器

【STM32合集】day2按键控制LED&光敏传感器控制峰鸣器 电路基础c语言基础main.ckey.c结果 实现一个键开关灯实验结果避坑 电路基础 运算放大器-在江科大51单片机b站视频&#xff08;AD/DA&#xff09;复习 原理&#xff1a;两个极端 同相输入端电压 》反相输入端 电压输出最…

基于RTOS(实时操作系统)的CMT液晶屏控制器驱动程序开发与实现

RTOS&#xff08;实时操作系统&#xff09;提供了一种有效的方式来管理和调度多任务系统&#xff0c;对于液晶屏控制器的驱动程序开发来说&#xff0c;RTOS能够提供良好的实时性和可靠性。本文以RTOS为基础&#xff0c;设计并实现了一个用于控制CMT液晶屏的驱动程序。在设计过程…

【android】rk3588-android-bt

文章目录 蓝牙框架HCI接口蓝牙VENDORLIBvendorlib是什么 代码层面解读vendorlib1、 vendorlib实现&#xff0c;协议栈调用2、协议栈实现&#xff0c;vendorlib调用&#xff08;回调函数&#xff09;2.1、 init函数2.2、BT_VND_OP_POWER_CTRL对应处理2.3、BT_VND_OP_USERIAL_OPE…

【LV13 DAY16 轮询与中断】

轮询实现按键实验 #include "exynos_4412.h"int main() {//GPX1_1设置为输入模式//GPX1.CONGPX1.CON & (~ (0XF<<4));while(1){if(!(GPX1.DAT&(1<<1))){printf("key pressed\n");while(!(GPX1.DAT&(1<<1)));}else{}}return…

i18n多国语言Internationalization的实现

i18n 是"Internationalization”的缩写&#xff0c;这个术语来源于英文单词中首尾字母“”和“n”以及中间的字符数(共计18个字符) 当我们需要开发不同语言版本时&#xff0c;就可以使用i18n多国语言的一个操作处理&#xff0c;i18n主要实现那一方面的内容呢&#xff1f;…

蓝桥杯省赛无忧 STL 课件17 map

01 map 02 multimap 03 unordered_map 04 代码示例

训练DAMO-YOLO(damoyolo_tinynasL25_S.py)

文章目录 参考链接1 准备数据1.1 转为COCO格式1.2 指明数据路径 2 设置训练配置文件&#xff0c;在configs/damoyolo_tinynasL25_S.py进行如下两块修改2.1 关于训练参数的设置2.2 根据自己数据集设置 3 开始训练4 调用tools/eval.py进行测试5 训练时可能遇到的报错5.1 RuntimeE…

Java生成四位数随机验证码

引言&#xff1a; 我们生活中登录的时候都要输入验证码&#xff0c;这些验证码是为了增加注册或者登录难度&#xff0c;减少被人用脚本疯狂登录注册导致的一系列危害&#xff0c;减少数据库的一些压力。 毕竟那些用脚本生成的账号都是垃圾账号 本次实践&#xff1a;生成这样的…

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级

文章目录 Resilience4j概述Resilience4j官方地址Resilience4j-RateLimiter微服务演示Payment processorPOM配置文件ServiceController Payment servicePOMModelServiceRestConfigController配置验证 探究 Rate Limiting请求三次 &#xff0c;观察等待15秒连续访问6次 Resilienc…

mysql原理--undo日志1

1.事务回滚的需求 我们说过 事务 需要保证 原子性 &#xff0c;也就是事务中的操作要么全部完成&#xff0c;要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况&#xff0c;比如&#xff1a; (1). 事务执行过程中可能遇到各种错误&#xff0c;比如服务器本身的错误&…

前端对接电子秤、扫码枪设备serialPort 串口使用教程

因为最近工作项目中用到了电子秤&#xff0c;需要对接电子秤设备。以前也没有对接过这种设备&#xff0c;当时也是一脸懵逼&#xff0c;脑袋空空。后来就去网上搜了一下前端怎么对接&#xff0c;然后就发现了SerialPort串口。 Serialport 官网地址&#xff1a;https://serialpo…

软件工程:黑盒测试等价分类法相关知识和多实例分析

目录 一、黑盒测试和等价分类法 1. 黑盒测试 2. 等价分类法 二、黑盒测试等价分类法实例分析 1. 工厂招工年龄测试 2. 规定电话号码测试 3. 八位微机测试 4. 三角形判断测试 一、黑盒测试和等价分类法 1. 黑盒测试 黑盒测试就是根据被测试程序功能来进行测试&#xf…

通过开源端点可见性改善网络安全响应

在当今复杂的数字环境中&#xff0c;企业内的许多不同端点&#xff08;从数据中心的服务器到咖啡店的笔记本电脑&#xff09;创建了巨大且多样化的攻击面。每个设备都存在网络安全威胁的机会&#xff0c;每个设备都有其独特的特征和复杂性。攻击者使用的多种攻击媒介不仅是一个…