ElementUI-tree拖拽功能与节点自定义

前言

在管理端会遇到多分类时,要求有层次展示出来,并且每个分类有额外的操作。例如:添加分类、编辑分类、删除、拖到分类等。

下面将会记录这样的一个需求实习过程。

了解需求

  1. 分类展示按层级展示
  2. 分类根据特定的参数展示可以操作的按钮,分类的操作有增、删、改
  3. 分类还支持拖拽功能,并不是所有的分类都支持拖拽
  4. 点分类去执行别的操作。例如:刷新数据(不实现)
  5. 增加分类之后刷新分类数据,当前选择的分类为增加的分类
  6. 删除分类后回到上一级分类
  7. 右击分类和点击操作按钮均可以弹出操作弹窗
  8. 点击分类前的箭头可展开和折叠分类

效果图

  • 分类展示

  • 分类操作的弹窗

组件库

采用ElementUI 中的 Tree树形控件、Dropdown下拉菜单

  • Tree树形控件:Element - The world's most popular Vue UI framework
  • Dropdown下拉菜单dropdown:Element - The world's most popular Vue UI framework

开始编码

搭建tree 组件

  •   html 部分:
<el-tree :data="classifyData" node-key="id" draggable ref="tree" :accordion="false" auto-expand-parent :default-expanded-keys="[checkedId]" :props="defaultProps":allow-drop="allowDrop" :allow-drag="allowDrag"@node-drag-start="handleDragStart" @node-drop="handleDrop"@node-click="nodeClick" @node-contextmenu="rightClick":show-checkbox="false" :check-strictly="true"  ><div class="custom-tree-node" slot-scope="{ node, data }"><span>{{ data.name }}</span> <span><el-dropdown type="primary" trigger="click" :ref="'messageDrop'+data.id" @visible-change="controlCheckedKeys"><span class="el-dropdown-link" @click.stop="setSeletKey(data.id)">  <img src="~@/../more-active.png" v-if="checkedKeys == data.id"  class="myicon-opt" /> <img src="~@/../more.png" v-else class="myicon-opt" /></span><el-dropdown-menu slot="dropdown"><el-dropdown-item v-if="data.is_add_classify"><div @click="openClassify(data.id,'新增子分类')"><img src="~@/../add.png" class="myicon-opt"/> 新增子分类</div></el-dropdown-item><el-dropdown-item v-if="data.is_edit_sort"><div @click="editClassify(data)"> <img src="~@/../edit.png" class="myicon-opt" /> 修改</div></el-dropdown-item><el-dropdown-item v-if="data.is_edit_sort"><div @click="delBefore(data.id,data.parent_id)"><img src="~@/../del.png" class="myicon-opt" />删除</div></el-dropdown-item></el-dropdown-menu></el-dropdown></span></div></el-tree>
  • css
<style lang="stylus" scoped>
.active{background: #F2F6F9;color: #409EFF;
}
.classify{padding : 0 16px;height: 40px;font-family: PingFangSC-Medium;font-weight: 500;font-size: 15px; line-height:40px;
}.el-tree ::v-deep {.el-tree-node__content{ @extend .classify;&:hover{@extend .active; }.el-tree-node__expand-icon.is-leaf{// display:nonemargin-left:-12px}}.is-checked > .el-tree-node__content{@extend .active;} 
} 
.custom-tree-node{display: flex;justify-content: space-between;width: 100%;
}
.myicon-opt{vertical-align: middle;width: 16px;height: 16px;
} 
</style>
  • js
<script>export default {props:{activeId:{type:[String,Number],default:''},classifyData:{type:Array,default:[]}},watch:{activeId: {handler(v,o){// v 值为0时, 0 == '' 值为trueif (typeof v == 'number') {this.checkedId = v this.$nextTick(()=>{this.$refs.tree.setCheckedKeys([v])}) }},immediate:true,deep:true },},data() {return {checkedId:'', checkedKeys:'', defaultProps: {children: 'child',label: 'name'},classifyCofig:{flag:false,Id: '',title:'',value:''}, }},methods: { // 点击分类名称nodeClick(data,node){ this.checkedId = data.id  this.$refs.tree.setCheckedKeys([data.id]) node.expanded = truethis.$emit('selectId',data.id)// console.log('node',data.id,node.parent)let addId  = [ data.id]if(node.parent.parent != null)  this.selectNode(addId,node.parent)// console.log('addId',addId)this.$emit('selectaddId', addId)},// 获取多层级的父类id加入到数组下标为0的位置selectNode(id,node){ id.unshift(node.data.id)if(node.parent.parent != null){this.selectNode(id,node.parent)} },// 右击分类rightClick(event,data, Node, element){ setTimeout(()=>{this.checkedKeys = data.id this.$refs['messageDrop'+data.id].show() })},// 点击操作按钮setSeletKey(k){ setTimeout(()=>{this.checkedKeys = k})},// 下拉菜单的异步监听,打开(true)还是隐藏(flase)controlCheckedKeys(flag){  if(!flag){this.checkedKeys = ''}},// 节点开始拖拽时触发的事件handleDragStart(node) {if(!node.data.is_edit_sort){return false} }, // 拖拽成功完成时触发的事件handleDrop(draggingNode, dropNode, dropType) {if(dropType == 'none') return // 准备排序参数可自行更改let params = {pk1: draggingNode.data.id,pk2: dropNode.data.id,direction:dropType == 'before' ? -1 : 1}this.orderClassify(params)}, /** *  拖拽时判定目标节点能否被放置。* @param {*} draggingNode * @param {*} dropNode * @param {*} type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后*/allowDrop(draggingNode, dropNode, type) {if (draggingNode.level === dropNode.level) { if (draggingNode.data.parent_id === dropNode.data.parent_id && dropNode.data.is_edit_sort) {// 向上拖拽 || 向下拖拽return type === "prev" || type === "next"}} else {// 不同级进行处理return false}},//判断节点能否被拖拽allowDrag(draggingNode) {if(!draggingNode.data.is_edit_sort){return false}return true }, async orderClassify(params){// 发送排序请求}, setClassCofig(flag,id,title,value){this.classifyCofig['flag'] = flagthis.classifyCofig['Id'] = idthis.classifyCofig['title'] = titlethis.classifyCofig['value'] = value},openClassify(pid,txt){this.setClassCofig(true,pid, txt ? txt : '新增分类','')   },editClassify(row){this.setClassCofig(true,row.id, '修改分类', row.name) }, closeAdd(){this.setClassCofig(false,'', '', '')},// 新增/修改分类async sureClassify(params){ let {value,Id} = this.classifyCofig// 通过value的值判断当前是新增还是修改// 刷新分类,cid 新分类的idlet refresh = { }if(value){ refresh.flag = false}else{ refresh.flag = true}  // 准备参数,发送请求// 请求成功后执行this.setClassCofig(false,'', '', '')refresh.cid = value? this.checkedId : res.data.data.idthis.$emit('refreshClass',refresh)},//判断分类是否可以删除async delBefore(id,pid){//1.自定义判断是否可以删除,//2.可以删去执行删除操作,this.sureDelete(id,pid)},//删除分类,删除后回到上一级async sureDelete(id,pid){//1.准备删除的接口使用数据//2.发起请求,请求成功后执行下面代码this.setClassCofig(false,'', '', '')let refresh = {flag: true,cid: pid}this.$emit('refreshClass',refresh)},}};
</script>

使用tree组件

  • html
 <PersonalTree :activeId="currentClassfiyId" :classifyData="classifyData"@selectId="changeSelectId" @selectaddId="setAddId" @refreshClass="refreshClass"/>
  • js
<script>
// 在此处引入tree组件命名为customTreeexport default{components:{customTree},data(){return{currentClassfiyId:'',addClassifyId:[],classifyData:[], }},mounted(){this.getClassList(true) },methods:{async getClassList(flagScene,cid){// console.log(flagScene,cid)// 发送请求,获取全部分类this.classifyData = res.data.data.classify this.currentClassfiyId = cid || this.classifyData?.[0].idif(flagScene){ // 可以去获取内容} }},refreshClass({flag,cid}){// 去刷新分类列表this.getClassList(flag,cid)},setAddId(val){this.addClassifyId = val},changeSelectId(id){this.currentClassfiyId = id// 可以去获取内容},}}
</script>   

classifyData的数据:

[{"id": 1033,"name": "一级分类","parent_id": 0, "level": 1,"child": [{"id": 1036,"name": "aaaaaaaaa","parent_id": 1033, "level": 2,"child": [],"is_edit_sort": true,"is_add_classify": true,"is_add_scene": true},{"id": 1035,"name": "aaaaa","parent_id": 1033,  "level": 2,"child": [{"id": 1037,"name": "a-1","parent_id": 1035, "level": 3,"child": [{"id": 1040,"name": "a-1-3","parent_id": 1037, "level": 4,"child": [],"is_edit_sort": true,"is_add_classify": false,"is_add_scene": true},{"id": 1038,"name": "a-1-1","parent_id": 1037, "level": 4,"child": [],"is_edit_sort": true,"is_add_classify": false,"is_add_scene": true}],"is_edit_sort": true,"is_add_classify": true,"is_add_scene": true}],"is_edit_sort": true,"is_add_classify": true,"is_add_scene": true}],"is_edit_sort": true,"is_add_classify": true,"is_add_scene": true
},{"id": 1032,"name": "测试分类b","parent_id": 0, "level": 1,"child": [],"is_edit_sort": true,"is_add_classify": true,"is_add_scene": true
},{"id": 1015,"name": "无操作区","parent_id": 0,"level": 1,"child": [],"is_edit_sort": false,"is_add_classify": false,"is_add_scene": false
}]

如有帮到您,请收藏+关注哦!!!

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

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

相关文章

四阶龙格库塔与元胞自动机

龙格库塔法参考&#xff1a; 【精选】四阶龙格库塔算法及matlab代码_四阶龙格库塔法matlab_漫道长歌行的博客-CSDN博客 龙格库塔算法 Runge Kutta Method及其Matlab代码_龙格库塔法matlab_Lzh_023016的博客-CSDN博客 元胞自动机参考&#xff1a; 元胞自动机&#xff1a;森林…

Leetcode Daily Challenge 1845. Seat Reservation Manager

1845. Seat Reservation Manager 题目要求&#xff1a;初始化一个SeatManager类包括默认构造函数和类函数&#xff0c;所有的seat初始化为true。reverse函数返回最小的true&#xff0c;然后把这个编号的椅子赋值为false。unreverse(seatNumber)函数把编号为seatNumber的椅子恢…

阿里云中的云服务器的ubuntu中的vim没有显示行号

没有行号&#xff1a; 在终端输入命令&#xff1a; vim ~/.vimrc set nu

【PC电脑windows环境下-[jetson-orin-NX]Linux环境下-下载工具esptool工具使用-相关细节-简单样例-实际操作】

【PC电脑windows环境下-[jetson-orin-NX]Linux环境下-下载工具esptool工具使用-相关细节-简单样例-实际操作】 1、概述2、实验环境3、 物品说明4-2、自我总结5、本次实验说明1、准备样例2、设置芯片3、编译4、下载5、验证 &#xff08;1&#xff09;windows环境下进行烧写1、下…

java泛型的深入 泛型还可以在很多地方进行定义 泛型类 泛型方法 泛型接口 泛型的继承和通配符 泛型类练习

文章目录 泛型的深入泛型还可以在很多地方进行定义泛型类泛型方法泛型接口 泛型的继承和通配符泛型类练习总结 泛型的深入 public static void main(String[] args) {//在没有泛型的时候怎么存储数据ArrayList listnew ArrayList();list.add(1);list.add("abc");//遍…

上海:竹云董事长董宁受邀在第三届“双区驱动,打造全球经济新引擎”国际合作论坛发言

作为中国最具活力的两大重要经济带&#xff0c;粤港澳和长三角两大湾区2022年GDP总量超过42万亿&#xff0c;占全国GDP总量的35%&#xff0c;对中国经济的重要性举足轻重。中国国际进口博览会是我国主动向世界开放市场的重大举措&#xff0c;是一个推动两地开放合作&#xff0c…

Ubuntu18.04安装pcl-1.12.1,make时报错:/usr/bin/ld: cannot find -lvtkIOMPIImage

解决方案&#xff1a; 在vtk安装包中&#xff0c;重新打开cmake-gui&#xff0c;然后勾选上VTK_Group_MPI和VTK_Group_Imaging。 cd VTK-8.2.0 cd build cmake-gui然后重新编译生成。 make -j8 # 或者j4,量力而行。 sudo make install 就可以解决了。 然后重新回到pcl安装…

V-REP和Python的联合仿真

机器人仿真软件 各类免费的的机器人仿真软件优缺点汇总_robot 仿真 软件收费么_dyannacon的博客-CSDN博客 课程地址 https://class.guyuehome.com/p/t_pc/course_pc_detail/column/p_605af87be4b007b4183a42e7 课程资料 guyueclass: 古月学院课程代码 旋转变换 旋转的左乘与…

论文阅读—— UniDetector(cvpr2023)

arxiv&#xff1a;https://arxiv.org/abs/2303.11749 github&#xff1a;https://github.com/zhenyuw16/UniDetector 一、介绍 通用目标检测旨在检测场景那种的一切目标。现有的检测器依赖于大量数据集 通用的目标检测器应该有两个能力&#xff1a;1、可以利用多种来…

数据库实验:SQL的数据视图

目录 视图概述视图的概念视图的作用 实验目的实验内容实验要求实验过程 视图概述 视图是由数据库中的一个表或多个表导出的虚拟表&#xff0c;其作用是方便用户对数据的操作 视图的概念 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一…

SQL审计是什么意思?目的是什么?有什么好处?

很多刚入行的运维小伙伴对于SQL审计不是很了解&#xff0c;不知道其是什么意思&#xff1f;使用SQL审计的目的是什么&#xff1f;使用SQL审计的好处有哪些&#xff1f;这里我们大家就来一起聊聊&#xff0c;仅供参考哈&#xff01; SQL审计是什么意思&#xff1f; 【回答】&…

CoCa论文笔记

摘要 计算机视觉任务中&#xff0c;探索大规模预训练基础模型具有重要意义&#xff0c;因为这些模型可以可以极快地迁移到下游任务中。本文提出的CoCa&#xff08;Contrastive Captioner&#xff09;&#xff0c;一个极简设计&#xff0c;结合对比损失和captioning损失预训练一…

24PL-18-50-1836、12PN-4.1-50-1836比例电磁铁控制器

12PG-2.2-40-1836、24PG-8.8-40-1836、12PT-40-1836、24PT-40-1836、12PL-2.2-40-1836、24PL-8.8-40-1836、12PN-2.2-40-1836、24PN-8.8-40-1836、12PG-4.1-50-1836、24PG-18-50-1836、12PT-4.1-50-1836、24PT-18-50-1836、12PL-4.1-50-1836、24PL-18-50-1836、12PN-4.1-50-183…

以订单退款流程为例,聊聊如何优化策略模式

如果有人问你什么是策略模式&#xff1f;你可以尝试这样回答 策略模式是一种行为设计模式&#xff0c;它允许在运行时根据不同的情况选择不同的算法策略。这种模式将算法的定义与使用的代码分离开来&#xff0c;使得代码更加可读、可维护和可扩展。 在策略模式中&#xff0c;通…

LeetCode 热题100——链表专题

一、俩数相加 2.俩数相加&#xff08;题目链接&#xff09; 思路&#xff1a;这题题目首先要看懂&#xff0c;以示例1为例 即 342465807&#xff0c;而产生的新链表为7->0->8. 可以看成简单的从左向右&#xff0c;低位到高位的加法运算&#xff0c;4610&#xff0c;逢…

ES7 装饰器

阅读能解决问题-&#xff1a; 1&#xff09;装饰器有什么用&#xff0c;主要功能&#xff1f; 2&#xff09;装饰器&#xff1f;减少引入&#xff0c;减少代码&#xff0c;可以扩展&#xff0c;不需要改原有方法的代码位置 3&#xff09;放置位置&#xff0c;可以是类、类成员&…

24张宇八套卷复盘(五)

张八&#xff08;&#xff09;94选择25填空20高数大题25线代大题12概率大题12 前言 临近考试冲刺阶段&#xff0c;感觉做过的卷子很难再提起精神去复盘&#xff0c;于是在这里进行一下复盘。 主要是对于整体试卷结构的把握&#xff0c;以及考试状态的复盘。 简单的卷子把会做的…

数据库设计,原来找到对的辅助工具这么简单

糟糕的数据库设计后果&#xff1f;随着时间的流逝&#xff0c;需要花更多的时间摆弄数据结构。在处理大型复杂项目时&#xff0c;这变成了一个更大的问题。 合适的数据库设计工具可以帮助我们节省大量时间&#xff0c;同时还会确保不会因使用不当丢失数据&#xff0c;在线数据库…

【RabbitMQ】RabbitMQ 消息的堆积问题 —— 使用惰性队列解决消息的堆积问题

文章目录 一、消息的堆积问题1.1 什么是消息的堆积问题1.2 消息堆积的解决思路 二、惰性队列解决消息堆积问题2.1 惰性队列和普通队列的区别2.2 惰性队列的声明方式2.3 演示惰性队列接收大量消息2.4 惰性队列的优缺点 一、消息的堆积问题 1.1 什么是消息的堆积问题 消息的堆积…

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较 分布式控制系统(DCSs)和可编程逻辑控制器(PLC)之间的区别可以归结为一个简单的足球比喻。你的指挥系统是你的船长。团队名单上的第一个名字&#xff0c;你的DCS是可靠的&#xff0c;勤奋的&#xff0c;控制着整个…