树形结构的勾选、取消勾选、删除、清空已选、回显、禁用

树形结构的勾选、取消勾选、删除、清空已选、回显、禁用

基本页面:

分为上传文件和编辑的页面

代码实现要点:

  • 上传文件页面:

    1. 点开选择范围弹窗,三个radio单选框都为可选状态,默认显示的是第一个单选框(按机构项目组)对应的内容

    2. 可以对树形数据进行勾选,勾选的数据展示在右边已选框内

    3. 可以对树形数据进行全选,取消全选

    4. 右边已选框内数据有对应的删除按钮,可以点击删除按钮或对已选数据进行删除

    5. 可以点击清空已选按钮对已选数据进行一次性全部删除

    6. 在左边树形数据取消勾选,右边已选框的数据也会对应发生变化

    7. 点击确定按钮但未确认上传时,再次打开弹框,页面中应把上一次选择的数据展示出来,且不能禁用,并同步展示在右边已选框内,同样可以对数据进行以上操作

    8. 点击确定并在上一层点击确认上传按钮,已经勾选的数据就会传给后端,同步新增到了页面中,后续可以对数据进行编辑操作来修改数据

  • 编辑页面:

    1. 点开选择范围弹窗,只有从后端返回的对应的单选框类型的单选框才能可选,其他的单选框都为禁用状态

    2. 树形数据显示的也是可选单选框对应的树形数据

    3. 从后端得到的上一次确认上传的数据,对数据进行禁用,即只能继续添加不能删除原有的

    4. 从后端得到的上一次确认上传的数据,对数据同步展示在右边已选框

    5. 从后端得到的上一次确认上传的数据,在右边已选框内不能存在删除按钮

    6. 可以继续勾选想要勾选的数据,会同步展示在右边已选框,有删除按钮,可以删除

    7. 点击全选,全选数据,点击反选,把除了从后端得到的上一次确认上传的数据都取消勾选,同时右边已选框也要同步展示

    8. 点击清空已选,把除了从后端得到的上一次确认上传的数据在右边已选框内删除,同时左边的树形结构也要同步取消勾选数据

    9. 点击确定按钮但未确认上传时,再次打开弹框,显示的勾选数据为上次点击确定前勾选的数据,禁用的数据也仅为从后端得到的上一次确认上传的数据,右边已选框也展示的是上次点击确定前勾选的数据,没有删除按钮的也仅为从后端得到的上一次确认上传的数据

    10. 点击确定并在上一层点击确认上传按钮,已经勾选的数据就会传给后端,同步更新到页面中,后续也可以对数据进行编辑操作来修改数据

代码设计:

单选框用到的是el-radio组件

<div class="person_top_nav"><span>选择签署范围</span><el-radio-group style="margin-left: 12px" v-model="searchRange" @change="handleSearchChange"><el-radio style="max-width: 90px" :disabled="!(SelectedType == 'clientOrganization') && disabledArr.length > 0" :label="1">按机构项目组</el-radio><el-radio style="max-width: 60px" :disabled="!(SelectedType == 'organization') && disabledArr.length > 0" :label="2">按事业部</el-radio><el-radio style="max-width: 90px" :disabled="!(SelectedType == 'branchCompany') && disabledArr.length > 0" :label="3">按合约归属公司</el-radio></el-radio-group>
</div>
  • 绑定的是searchRange,点击事件调用的函数是handleSearchChange()函数

  • :disabled="!(SelectedType == 'clientOrganization') && disabledArr.length > 0" 是上传文件和编辑页面对单选框是否禁用的设置,即:第一个按机构项目组被禁用的时候是:在编辑页面disabledArr.length > 0,并且得到的从后端返回的类型不等于clientOrganization(机构项目组)

左边树形数据和右边已选框用到的都是el-tree组件

左边树形数据:

<el-tree:data="dataTree" // 展示数据:default-checked-keys="checkboxId" // 默认勾选节点show-checkbox // 节点可被选择v-loading="loading"class="filter-tree" // 绑定类node-key="value" // 树节点唯一标识ref="tree" // 绑定树,可后续调用方法:props="defaultProps" // 配置选项 defaultProps: { children: 'children', label: 'label'}@check-change="getCheckedNodes" // 节点选中状态发生变化时的回调
>
</el-tree>
  • data属性是绑定展示的数据,这里绑定的是dataTree

  • default-expand-all属性是绑定默认勾选的节点的 key 的数组,绑定的数据为checkboxId,是默认勾选的数据value数组

  • node-key属性是每个树节点用来作为唯一标识的属性,整棵树应该是唯一的,这里绑定的是节点的value

  • check-change事件是节点选中状态发生变化时的回调,绑定着函数getCheckedNodes()

右边已选框数据:

<el-tree :data="isSelectedData" :props="defaultProps" :default-expand-all="true"><span class="custom-tree-node" slot-scope="{ node, data }"><span class="tree_label">{{ node.label }}</span><el-buttonclass="remove_button"v-if="!(node.disabled || data.ifShow)"type="text"size="medium"@click="() => remove(node, data)">×</el-button></span>
</el-tree>

绑定的数据为isSelectedData,default-expand-all默认展开所有节点

重要数据:

dataTree:调用选择radio的接口数据,也就是一棵树

checkboxId:左边树的默认勾选节点,是一个value数组

isSelectedData:右边已选框的展示数据,也就是左边树的数据

searchRange:radio单选框绑定的数据

disabledArr:原始数据,应被禁用和默认勾选,展示【从父组件传入】

peList:上一次勾选提交的数据,应被默认勾选和展示(每一次点击确定后都会被改变)【从父组件传入】

oldDisabledArr:disabledArr得来

oldDisabledArrId:disabledArr得来

SelectedType:从父组件传入的选择范围类型

用到的el-tree方法:

setCheckedNodes():设置目前勾选的节点,使用此方法必须设置 node-key 属性,(nodes) 接收勾选节点数据的数组

getCheckedNodes():若节点可被选择(即 show-checkboxtrue),则返回目前被选中的节点所组成的数组,(leafOnly, includeHalfChecked) 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false 2. 是否包含半选节点,默认值为 false

setChecked():通过 key / data 设置某个节点的勾选状态,使用此方法必须设置 node-key 属性,(key/data, checked, deep) 接收三个参数,1. 勾选节点的 key 或者 data 2. boolean 类型,节点是否选中 3. boolean 类型,是否设置子节点 ,默认为 false

代码执行流程:

编辑页面:

  1. 点击选择范围弹框,调用open()方法,打开弹框,根据是否有从父组件传入的peList(上一次选择的数据)来判断是上传文件还是编辑页面

    • 上传文件:默认调用机构项目组接口和展示机构项目组树形数据

    • 编辑:调用从父组件传入的SelectedType(选择范围类型),在handleSearchChange()函数内调用对应的接口和展示对应的树形数据

    async opened() {// 存在已选数据this.disabledArr.forEach((item, index) => {this.$set(this.oldDisabledArr, index, item);});this.disabledArr.forEach((item, index) => {this.$set(this.oldDisabledArrId, index, item.value);});
    ​// 打开选择范围弹框this.dialogVisible = true;// clientOrganization 机构项目组   organization 事业部   branchCompany 合约归属公司
    ​if (!this.peList) {// 上传文件 默认选中机构项目组await this.getInstitutionIssueList();} else {// 编辑if (this.SelectedType === 'clientOrganization') {this.searchRange = 1;} else if (this.SelectedType === 'organization') {this.searchRange = 2;} else if (this.SelectedType === 'branchCompany') {this.searchRange = 3;}// 调用对应接口await this.handleSearchChange();// 初始化this.init();}
    }
  2. 调用init()函数,执行的逻辑为

    init() {this.$nextTick(() => {// 给checkboxId赋值this.checkboxId = [];this.peList.map((item, index) => this.$set(this.checkboxId, index, item.value));this.$refs.tree.setCheckedNodes(this.peList);this.$forceUpdate();
    ​// 把禁用节点显示在右边this.getCheckedNodes();
    ​// 禁用已选节点this.reShowDisabled(this.dataTree, this.oldDisabledArrId);
    ​// 去掉父节点的删除按钮this.getParentValueList();});
    }
    • 初始化checkboxId,从peList中得到(上一次选择的数据)【注意:不是从disabledArr中得到,因为如果第一次勾选数据后点击确认,以后在确认上传前再次点击选择范围,页面不会回显上一次勾选的数据,但是确认上传后,提交给后端的又是上一次勾选的数据,不符合逻辑】

    • 通过el-tree的方法setCheckedNodes()设置目前勾选的节点【注意:一定要执行这一步,否则后续指定删除、清空已选、取消勾选并确定后,在确认上传前的再次点击选择范围,被删除的数据节点还是会被勾选和展示在已选框,猜测的原因是没有取消勾选删除的节点数据,即再次设置勾选节点,而不是通过default-expand-all属性来自动勾选】

    • 调用getCheckedNodes()函数,把上一次勾选提交的数据节点展示在右边已选框

      • getCheckedNodes()函数,【这个函数也绑定着左边树的change回调】,里面的逻辑为:调用el-tree的getCheckedNodes()方法,获取目前被选中的节点的数组checkedList,然后用checkedList作为参数调用depthTraversal()函数,递归来返回选中的树形节点,并赋值给isSelectedData,就同步展示在右边已选框了

      // 选择数据 -> 展示 el-tree回调
      getCheckedNodes() {const checkedList = this.$refs.tree.getCheckedNodes(false, true);this.isSelectedData = this.depthTraversal(JSON.parse(JSON.stringify(this.dataTree)), checkedList);
      }
      // 返回选中的数据列表
      depthTraversal(list, filterList) {const addObj = (list) => {return list.filter((v) => {if (v.children && filterList.findIndex((val) => val.value === v.value) !== -1) {v.children = addObj(v.children);return v;}return filterList.findIndex((val) => val.value === v.value) !== -1;});};return addObj(list);
      }
    • 调用reShowDisabled()函数,把禁用节点进行禁用

      • 传入的参数为oldDisabledArrId(感觉等同于checkboxId),利用闭包写一个递归函数并调用,找到value在oldDisabledArrId数组中的节点:

        • 给它设置disabled为true的属性,实现禁用

        • 调用setdisabledParentList()函数,把它的parentValue放入disabledParentList中,便于后续删除掉父节点的删除按钮【存在逻辑是SelectedType是branchCompany时取反parentValue,树形节点的唯一性问题】

      // 回显禁用节点 checkboxId 禁用节点value数组
      reShowDisabled(list, checkboxId) {this.disabledParentList = [];const disabledObj = (list) => {list.forEach((v) => {if (checkboxId.findIndex((val) => val === v.value) !== -1) {this.$set(v, 'disabled', true);this.setdisabledParentList(v);// console.log('禁用', v);}if (v.children) {disabledObj(v.children);}});};disabledObj(list);
      }
    • 调用getParentValueList()函数,去掉父节点的删除按钮

      • 利用闭包写递归函数,在树节点中找到value在disabledParentList中的节点,为它设置ifShow为true的属性,实现父节点删除按钮的去掉

      // 获取需要隐藏删除按钮的所有父节点,设置ifShow属性
      getParentValueList() {const ifShowObj = (list) => {list.forEach((v) => {if (this.disabledParentList.findIndex((val) => val === v.value) !== -1) {this.$set(v, 'ifShow', true);}if (v.children) {ifShowObj(v.children);}});};ifShowObj(this.dataTree);
      }
    • 初始化完成

  3. 对左边树形数据进行勾选和取消勾选,都会触发树的change事件,调用getCheckedNodes()函数,逻辑如上

    // 选择数据 -> 展示 el-tree回调
    getCheckedNodes() {const checkedList = this.$refs.tree.getCheckedNodes(false, true);this.isSelectedData = this.depthTraversal(JSON.parse(JSON.stringify(this.dataTree)), checkedList);
    }
  4. 对右边已选框的数据点击删除按钮进行删除,调用remove()函数,调用el-tree的setChecked()方法,取消对对应节点的勾选,然后再次调用getCheckedNodes()函数

    // delete 右边移除选中的数据
    remove(node, data) {this.$refs.tree.setChecked(data.value, false, true);this.getCheckedNodes();
    }
  5. 点击清空已选按钮,调用empty()函数,在dataTree中过滤出除了禁用节点(oldDisabledArr/disabledArr)以外的节点,通过el-tree的setChecked()方法设置节点为取消勾选

    //点击清空时清空所有人员跟人员id
    empty() {// 过滤出除了所有外的数据,取消勾选const aa = this.dataTree.filter((item) => this.oldDisabledArr.findIndex((val) => val.value === item.value) === -1);aa.map((item) => this.$refs.tree.setChecked(item.value, false, true));this.checkAll = false;
    }
  6. 点击全选或反选按钮,调用handleCheckAllChange()函数,也是在dataTree中过滤出除了禁用节点(oldDisabledArr/disabledArr)以外的节点:

    • 若是全选,则用setChecked()方法设置节点为勾选

    • 若是反选,则用setChecked()方法设置节点为取消勾选

    // 全选反选
    handleCheckAllChange() {console.log('checkAll', this.checkAll);const aa = this.dataTree.filter((item) => this.oldDisabledArr.findIndex((val) => val.value === item.value) === -1);if (this.checkAll) {console.log('全选');aa.map((item) => this.$refs.tree.setChecked(item.value, true, true));} else {console.log('反选');console.log(this.disabledArr);aa.map((item) => this.$refs.tree.setChecked(item.value, false, true));}
    }
  7. 点击确定按钮,调用surePromoter()方法,校验通过后,通过getCheckedNodes()方法得到目前所有被选择的节点赋值给resultSelectedData:

    • 若是上传文件,则通过$emit传给父组件对应的radio类型和resultSelectedData

    • 若是编辑,则通过$emit传给父组件SelectedType和resultSelectedData

    然后关闭选择范围弹框

    surePromoter() {if (this.isSelectedData.length === 0) {this.$message({message: '请选择成员!',type: 'warning'});return;}
    ​// 提交的listconst resultSelectedData = this.$refs.tree.getCheckedNodes(false, false);// clientOrganization 机构项目组   organization 事业部   branchCompany 合约归属公司
    ​if (this.oldDisabledArr.length === 0) {// 上传文件if (this.searchRange === 1) {this.$emit('getOrgList', 'clientOrganization', resultSelectedData, this.checkAll);} else if (this.searchRange === 2) {this.$emit('getOrgList', 'organization', resultSelectedData, this.checkAll);} else if (this.searchRange === 3) {this.$emit('getOrgList', 'branchCompany', resultSelectedData, this.checkAll);}} else {//编辑this.$emit('getOrgList', this.SelectedType, resultSelectedData, this.checkAll);}
    ​this.dialogVisible = false;
    }

还存在的问题:

1. 全选反选按钮是否勾选问题,已解决

2. 树形节点全选反选的速度较慢,待改进 

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

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

相关文章

人工智能的未来:畅想智能新时代

人工智能正在改变我们的世界&#xff0c;它将带我们走向何方&#xff1f; 著名神经科学家、Numenta 公司创始人杰夫•霍金斯 Jeff Hawkins 在其著作《人工智能的未来》中&#xff0c;描绘了一幅人工智能发展的光明图景。他认为&#xff0c;人工智能将超越人类智能&#xff0c;…

视觉与味蕾的交响:红酒与艺术的无界狂欢,震撼你的感官世界

在浩瀚的艺术海洋中&#xff0c;红酒以其不同的魅力&#xff0c;成为了一种跨界整合的媒介。当雷盛红酒与艺术相遇&#xff0c;它们共同呈现出一场特别的视觉盛宴&#xff0c;让人沉醉在色彩与光影的交织中&#xff0c;感受红酒与艺术的无界碰撞。 雷盛红酒&#xff0c;宛如一件…

AI作画Prompt不会写?Amazon Bedrock Claude3.5来帮忙

最新上线的Claude3.5 Sonnet按照官方介绍的数据来看&#xff0c;在多方面超越了CPT-4o&#xff0c;是迄今为止最智能的模型。 而跟上一个版本相比&#xff0c;速度是Claude 3 Opus的两倍&#xff0c;成本只有其五分之一。 Claude3.5 Sonnet不仅擅长解释图表、图形或者从不完…

Day28:回溯法 491.递增子序列 46.全排列 47.全排列 II 332.重新安排行程 51. N皇后 37. 解数独

491. 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序列的一种特殊情…

网络安全学习路线图(2024版详解)

近期&#xff0c;大家在网上对于网络安全讨论比较多&#xff0c;想要学习的人也不少&#xff0c;但是需要学习哪些内容&#xff0c;按照什么顺序去学习呢&#xff1f;其实我们已经出国多版本的网络安全学习路线图&#xff0c;一直以来效果也比较不错&#xff0c;本次我们针对市…

学会python——生成日志信息(python实例十二)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、生成日志信息 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、总结 1、认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

Vue-双向数据绑定指令

v-model指令 双向数据绑定就是当数据设置给表单元素时&#xff0c;修改这个数据会修改表单元素的值&#xff0c; 修改表单元素的值同样也会修改这个数据 <body><div id"app"><input type"text" v-model"name"><p>{{name…

利用 Swifter 加速 Pandas 操作的详细教程

利用 Swifter 加速 Pandas 操作的详细教程 引言 Pandas 是数据分析中常用的库&#xff0c;但在处理大型数据集时效率可能会较低。Swifter 提供了一种简便的方法&#xff0c;通过并行处理来显著加速 Pandas 操作。 Swifter 简介 Swifter 是一个开源库&#xff0c;旨在自动优…

一个项目学习Vue3---创建一个 Vue 应用

步骤1&#xff1a;安装符合要求的node版本 目前官网要求使用的node.js版本为18.3及其以上 所以我们要安装node.js 18.3及其以上版本 NVM安装教程&#xff1a;一个项目学习Vue3---NVM和NPM安装-CSDN博客 若不想安装NVM&#xff0c;可以直接下载适合自己的node版本Node.js — …

Go 延迟调用 defer

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

来了,你的第一个AI智能体

为了能直观的感受AI智能体&#xff0c;最好的方法是亲手开发一个智能体&#xff0c;当然&#xff0c;这个智能体不能太复杂&#xff0c;否则难度太大&#xff0c;会打击我们的热情的&#xff0c;热情是很宝贵的资源&#xff0c;必须要小心呵护。 我们在国内AI平台语聚AI上搭建…

RK3588 Android13 TvSetting 中增加 WebView 切换菜单

前言 电视产品,客户要求在设置中设备偏好设置子菜单下增加一个 WebView切换菜单,一开始不知道怎么下手,后来想起来在设置开发者选项里有一个类似的菜单, 去把实现逻辑搞出来应该就ok。 效果图 TvSetting 部分修改文件清单 packages/apps/TvSettings/Settings/res/values…

【吊打面试官系列-Mysql面试题】为表中得字段选择合适得数据类型

大家好&#xff0c;我是锋哥。今天分享关于 【为表中得字段选择合适得数据类型】面试题&#xff0c;希望对大家有帮助&#xff1b; 为表中得字段选择合适得数据类型 字段类型优先级: 整形>date,time>enum,char>varchar>blob,text 优先考虑数字类型&#xff0c;其次…

npm-check【实用教程】升级项目中的依赖

安装 npm-check npm i -g npm-check检查项目中的依赖 npm-check会显示项目中没有使用&#xff0c;以及有新版本的依赖 升级项目中的依赖 npm-check -u方向键上下可以移动图中左侧的箭头空格键可选中/取消选中标注为 Major Update 和 Non-semver 类的版本&#xff0c;需去官网查…

Python课程设计:python制作俄罗斯方块小游戏

基于python的俄罗斯方块小游戏 目录 基于python的俄罗斯方块小游戏 1.概述 1.1 摘要 1.2 开发背景 1.3 开发环境 1.4 实现功能 2.代码描述 2.1 模块导入 2.2 初始化变量 2.3 播放音乐 2.4 创建方块类 2.5 绘制游戏地图 2.6 游戏初始化 2.7 绘制有边框矩形 2.8 …

【小沐学AI】Python实现语音识别(Whisper-Web)

文章目录 1、简介2、下载2.1 openai-whisper2.2 whisper-web 结语 1、简介 https://openai.com/index/whisper/ Whisper 是一种自动语音识别 &#xff08;ASR&#xff09; 系统&#xff0c;经过 680,000 小时的多语言和多任务监督数据的训练&#xff0c;从网络上收集。我们表…

VLAN的工作原理、划分方式、配置示例

随着网络技术的飞速发展&#xff0c;VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;技术已成为网络分割和管理的重要工具。它不仅能提升网络的安全性和效率&#xff0c;还极大地增强了网络管理的灵活性。 VLAN概述 VLAN&#xff0c;即虚拟局…

Web前端第四次作业

目录 一、编写一个函数&#xff0c;形参是一个数组&#xff0c;返回数组中所有数字的平均值 二、编写一个函数&#xff0c;形参是一个数组&#xff0c;返回数组中的最大值 三、编写一个函数&#xff0c;形参是一个字符串&#xff0c;统计该字符串中每个字母出现的次数&#…

大数据之路 读书笔记 Day1

大数据之路 读书笔记 Day1 阿里巴巴大数据系统体系架构图 1. 数据采集层 #mermaid-svg-YqqD2w3qV6jc2aGP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YqqD2w3qV6jc2aGP .error-icon{fill:#552222;}#mermaid-sv…

中文检测程序(静态代码扫描)

欢迎您关注我们&#xff0c;经常分享有关Android出海&#xff0c;iOS出海&#xff0c;App市场政策实时更新&#xff0c;互金市场投放策略&#xff0c;最新互金新闻资讯等文章&#xff0c;期待与您共航世界之海。 在前些日子&#xff0c;给大家安利了我们在用的AS中文实时检测插…