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.mzph.cn/news/133987.shtml

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

相关文章

C语言——switch语句判断星期

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int day 0;scanf("请输入1-7之间的整数&#xff1a;%d",&day);switch(day){case 1:printf("星期一\n");break;case 2:printf("星期二\n");break;case 3:printf(&quo…

Java基于springboot开发的景点旅游项目

演示视频 https://www.bilibili.com/video/BV1cj411Y7UK/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 主要功能&#xff1a;用户可浏览搜索旅游景点&#xff08;分为收费和免费景点&#xff09;&#xff0c;购票&#xff08;支持多规格套餐购票&am…

【Node.js入门之—1.1Node.js 简介】

Node.js入门之—1.1Node.js 简介 文章目录 Node.js入门之—1.1Node.js 简介什么是 Node.js错误说法 Node.js 的特点跨平台三方类库自带http服务器非阻塞I/O事件驱动单线程 Node.js 的应用场合适合用Node.js的场合不适合用Node.js的场合弥补Node.js不足的解决方案 什么是 Node.j…

Linux收发包工具

发包工具 sendip 安装 sudo apt-get install sendip使用 #UDP: 从192.168.9.142向192.168.9.132的8889端口发送udp数据包"hello132" sendip -p ipv4 -is 192.168.9.142 -p udp -ud 8889 -d "hello132" 192.168.9.132收包工具 tcpdump 使用 -a #…

springboot(ssm 旅游管理系统 旅游规划平台 Java(codeLW)

springboot(ssm 旅游管理系统 旅游规划平台 Java(code&LW) 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff…

cordova Xcode打包ios以及发布流程(ionic3适用)

第一步 1、申请iOS证书 2、导入证书到钥匙串 第二步 1、xcode配置iOS证书 1.1用Xcode打开你的项目&#xff08;我的Xcode版本是新版&#xff09; 修改如下图 回到基本信息设置界面&#xff0c;Bundie 这项填写&#xff0c;最先创建的那个appid&#xff0c;跟创建iOS描述文件时选…

决策式AI与生成式AI

人工智能中深度学习&#xff0c;是一种受人脑的生物神经网络机制启发&#xff0c;并模仿人脑来解释、处理数据的机器学习技术&#xff0c;它能自动对数据进行特征提取、识别、决策和生成。它可以从不同的维度进行划分&#xff0c;如果按模型的特点来划分可分为决策式AI和生成式…

2023年中国金融控股公司研究报告

第一章 行业概况 1.1 定义 金融控股公司这一术语最初源自美国&#xff0c;特别是在美国的《金融服务法案》关于银行控股公司组织结构的条文中&#xff0c;首次出现了“金融控股公司”&#xff08;Financial Holding Company&#xff09;这一法律术语&#xff0c;尽管法案中并…

红黑数原理及存在原因

我红黑树那么牛&#xff0c;你们为什么不用&#xff1f;_哔哩哔哩_bilibili 面试时经常会被问到红黑树&#xff0c;它到底有什么优点呢&#xff1f; 对于查找数据&#xff0c;数组二分查询速度最快&#xff0c;时间复杂度为O(logN)。但是如果增加和删除数据&#xff0c;数组就…

ARMday02(汇编语法、汇编指令)

汇编语法 汇编文件中的内容 1.伪操作&#xff1a;在汇编程序中不占用存储空间&#xff0c;但是可以在程序编译时起到引导和标识作用 .text .global .glbal .if .else .endif .data .word.... 2.汇编指令&#xff1a;每一条汇编指令都用来标识一个机器码&#xff0c;让计算机做…

使用 Python、XML 和 YAML 编写 ROS 2 Launch 文件

系列文章目录 ROS2 重要概念 ament_cmake_python 用户文档 ROS2 ament_cmake 用户文档 使用 rosdep 管理 ROS 2 依赖项 文章目录 系列文章目录前言一、Launch 文件示例1.1 Python 版本1.2 XML 版本1.3 YAML 版本 二、从命令行使用 Launch 文件1. Launching2. 设置参数3. 控制海…

idea中的.idea文件夹以及*.iml文件(新版idea没有*.iml文件了),新旧版idea打开同一个项目会不会出现不兼容

一、背景 我们有可能会在同一台电脑上安装2个 intellj idea。比如一个community edition一个ultimate edition&#xff08;一个安装板一个绿色解压版&#xff09; 当然了&#xff0c;两个idea之间可能版本号也会有差。 这篇文章就来讨论两个问题&#xff0c;一是关于idea产生…

深度学习中的数据类型介绍:FP32, FP16, TF32, BF16, Int16, Int8 ...

文章目录 0. 前言1. 数据的存储方式2. 不同数据类型介绍2.1 深度学习中常用的数据类型2.2 BF16 类型的优势2.3 不同数据类型的使用场景 0. 前言 相比于 CPU&#xff0c;GPU 在架构设计时将更多的晶体管用于数据处理&#xff0c;而不是数据缓存和流量控制&#xff0c;因此可以高…

致:CSGO游戏搬砖人的一封信

最近大家还在坚持操作CSGO游戏搬砖项目不&#xff1f; 这个项目虽是稳赚项目&#xff0c;但也有行情好和行情不好的时候&#xff0c;平台的大中小各种活动的举办&#xff0c;都会对我们的项目造成一定影响。行情的上下波动势必然会影响卡价的波动&#xff0c;影响选品的快慢&a…

客户案例:CAC2.0监测异常账号行为,缓解暴力破解攻击

客户背景 某IT互联网公司专注于高精度导航定位技术的研发、制造和产业化推广&#xff0c;是国内高精度导航定位产业的领先企业之一。该公司以上海为总部&#xff0c;旗下拥有20国内省级本地化服务机构&#xff0c;并且其业务覆盖海外市场&#xff0c;公司产品和解决方案在不同…

棱镜七彩亮相工控中国大会,以软件供应链安全助力新型工业化高质量发展

2023年11月1日-3日&#xff0c;2023第三届工控中国大会在苏州国际会议中心举办&#xff0c;本届大会由中国电子信息产业发展研究院、中国工业经济联合会、国家智能制造专家委员会、国家产业基础专家委员会、江苏省工业和信息化厅、江苏省国有资产监督管理委员会、苏州市人民政府…

HTML 表格

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格标签</title>/* <style>.yun {widt…

C++学习 --函数

目录 1&#xff0c; 函数定义 1-1&#xff0c; 有返回值 1-2&#xff0c; 无返回值 2&#xff0c; 函数声明 3&#xff0c; 函数分文件编写 3-1&#xff0c; 创建自定义头文件 3-2&#xff0c; 创建源文件 3-3&#xff0c; 自定义头文件中编写函数声明 3-4&#xff0c…

北京陪诊小程序|陪诊系统开发|陪诊小程序未来发展不可小觑

近几年随着互联网快速发展&#xff0c;各行业领域都比较注重线上服务系统&#xff0c;通过陪诊小程序开发可以满足更多用户使用需求&#xff0c;同时还能提高用户使用体验。现在陪诊类的软件应用得到全面推广&#xff0c;在医疗行业当中陪诊小程序更贴近用户生活&#xff0c;可…

【漏洞复现】Apache_Tomcat7+ 弱口令 后台getshell漏洞

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 说明内容漏洞编号漏洞名称Tomcat7 弱口令 && 后台getshell漏洞漏洞评级高…