动图演示:

背景:

一开始做功能的时候没有增加排序的索引(sort-index),后来要求做拖拽排序功能;所以写了这个不需要初始排序就可以完成的拖拽功能;如果是table表格排序逻辑和这个相似,这里拿这个angular框架的树形菜单来做例子;

核心逻辑:

1,查询列表需要通过多字段进行排序如:SortIndex(新创建的字段,默认值为0),创建时间,Id
2,编写拖拽逻辑,同级别的互相移动。移动后修改全部SortIndex(索引字段);
3,不同级别的相互合并或拆分(修改父Id即可)。移动后修改全部SortIndex(索引字段);

代码展示:

前端方法:

                <nz-tree #studentgroupTree [nzData]="treeData" nzShowIcon [nzSearchValue]="searchTreeNodeValue" (nzSearchValueChange)="searchTreeNode($event)"
nzDraggable nzBlockNode [nzBeforeDrop]="beforeDrop" (nzOnDrop)="onDropTreeNode($event)" (nzClick)="clickTreeNode()" >
</nz-tree>

treeData就是调用后台查询的方法返回的数据集合;

其中 [nzBeforeDrop]表示拖拽前的验证;[onDropTreeNode]表示拖拽的方法,在ts或js中调用后台方法;

后端查询方法:

        public object GetTreeData()
{
List<Organization> allPermissionOrgList = new List<Organization>() { }; allPermissionOrgList = allPermissionOrgList.OrderBy(t => t.SequenceNo).ThenBy(t => t.CreatedTime).ThenBy(t => t.Id).ToList(); return allPermissionOrgList;
}

排序顺序尽量按照先索引然后创建时间其次ID的排序;

后端拖拽方法:

        /// <summary>
/// 移动学员分组
/// </summary>
/// <param name="dragNodeid">拖拽对象</param>
/// <param name="nodeid">目标对象</param>
/// <param name="pos">见上文描述</param>
/// <returns></returns>
public virtual async Task<OperationResult> MoveStudentTreeNode(int dragNodeid, int nodeid, int pos)
{
var dragNode = OrganizationRepository.Get(dragNodeid);
if (dragNode == null)
{
return new OperationResult(OperationResultType.NoChanged);
}
var node = OrganizationRepository.Get(nodeid);
if (node == null)
{
return new OperationResult(OperationResultType.NoChanged);
} List<Organization> GroupList = new List<Organization>(); var OrganizationsList = Organizations.Where(x => x.OrganizationType == 1 && x.DeletedTime == null);
if (node.ParentId != null)
{//有父级,表示本身是子级
GroupList = OrganizationsList.Where(x => x.ParentId == node.ParentId).ToList();
}
else if (node.ParentId == null && pos == 0)
{//没有父级,并且pos等于0 代表拖拽到中间位置了
GroupList = OrganizationsList.Where(x => x.ParentId == node.Id).ToList();
}
else
{//没有父级,表示本身是父级
GroupList = OrganizationsList.Where(x => x.ParentId == null).ToList();
}
GroupList = GroupList.Distinct().OrderBy(t => t.ParentId).ThenBy(t => t.SequenceNo).ThenBy(t => t.Id).ToList(); List<Organization> editedNodeList = new List<Organization>();
string belongId = string.Empty;
switch (pos)
{
case 0:
dragNode.ParentId = node.Id;
belongId = node.Path.Split(',', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
if (!string.IsNullOrEmpty(belongId))
await UserRepository.QueryAsNoTracking().Where(x => x.BelongToRootId == dragNode.Id).UpdateFromQueryAsync(x => new User { BelongToRootId = Convert.ToInt32(belongId) });
SetTreePath(dragNode);
GroupList.Insert(0, dragNode);
for (int i = 0; i < GroupList.Count; i++)
{
var item = GroupList[i];
item.SequenceNo = i + 1;
editedNodeList.Add(item);
}
break;
case -1:
case 1:
if (dragNode.ParentId == node.ParentId)
{//如果是同一目录拖拽
GroupList.Remove(dragNode); var itemIndex = GroupList.IndexOf(node);
if (pos == -1)
GroupList.Insert(itemIndex + 0, dragNode);
else
GroupList.Insert(itemIndex + 1, dragNode); for (int i = 0; i < GroupList.Count; i++)
{
var item = GroupList[i];
item.SequenceNo = i + 1;
editedNodeList.Add(item);
}
}
else
{//如果是不同目录拖拽
dragNode.ParentId = node.ParentId;
belongId = node.Path.Split(',', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
if (!string.IsNullOrEmpty(belongId))
await UserRepository.QueryAsNoTracking().Where(x => x.BelongToRootId == dragNode.Id).UpdateFromQueryAsync(x => new User { BelongToRootId = Convert.ToInt32(belongId) });
//UpdateBelongToRootIds(dragNode.Id, Convert.ToInt32(belongId));
SetTreePath(dragNode); var itemIndex = GroupList.IndexOf(node);
if (pos == -1)
GroupList.Insert(itemIndex + 0, dragNode);
else
GroupList.Insert(itemIndex + 1, dragNode); for (int i = 0; i < GroupList.Count; i++)
{
var item = GroupList[i];
item.SequenceNo = i + 1;
editedNodeList.Add(item);
}
}
break;
default:
break;
}
if (editedNodeList.Count > 0)
await OrganizationRepository.UpdateAsync(GroupList.ToArray());
return new OperationResult(OperationResultType.NoChanged); }

结语:

整体核心代码就是拖拽方法那里,感觉写的还是比较通用的。如有疑问,欢迎评论。最后祝大家中秋国庆节日快乐;

c# 拖拽列表顺序 | 拖拽合并分组 | 移除分组功能的更多相关文章

  1. 【UWP】拖拽列表项的排序功能实现

    在一些允许用户自定义栏目顺序的app(如:凤凰新闻.网易云音乐等),我们可以方便地拖拽列表项来完成列表的重新排序,进而完成对栏目顺序的重排.这个功能很人性化,而实现起来其实很简单(甚至都不用写什么后台 ...

  2. Android高级控件(六)——自定义ListView高仿一个QQ可拖拽列表的实现

    Android高级控件(六)--自定义ListView高仿一个QQ可拖拽列表的实现 我们做一些好友列表或者商品列表的时候,居多的需求可能就是需要列表拖拽了,而我们选择了ListView,也是因为使用L ...

  3. Android学习系列(11)--App列表之拖拽ListView(下)

    接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果. 7.重写onTouchEvent()方法.     在这个方法中我们主要是处理 ...

  4. Android学习系列(10)--App列表之拖拽ListView(上)

     研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.      鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...

  5. Android学习系列--App列表之拖拽ListView(下)

    接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果. 7.重写onTouchEvent()方法.     在这个方法中我们主要是处理 ...

  6. Android学习系列--App列表之拖拽ListView(上)

    研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.      鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. 一 ...

  7. Qt之股票组件-自选股--列表可以拖拽、右键常用菜单

    目录 一.开头嘴一嘴 二.效果展示 三.自选股列表 1.列表初始化 2.添加Item 3.右键菜单 4.拖拽Item 5.刷新数据 四.相关文章 原文链接:Qt之股票组件-自选股--列表可以拖拽.右键 ...

  8. 实现拖拽列表-微信小程序

    之前在网上搜索拖拽列表的实现时,发现了有好多的方法都是基于像素位置的计算实现的,这种方法要求列表元素的大小以及列表的位置有着非常严格的要求,修改和拓展起来非常的麻烦.于是我自己动手实现了一个基于页面元 ...

  9. 基于html5拖拽api实现列表的拖拽排序

    基于html5拖拽api实现列表的拖拽排序 html代码: <ul ondrop="drop_handler(event);" ondragover="dragov ...

  10. WPF拖拽文件(拖入拖出),监控拖拽到哪个位置,类似百度网盘拖拽

    1.往wpf中拖文件 // xaml <Grid x:Name="grid_11" DragOver="Grid_11_DragOver" Drop=&q ...

随机推荐

  1. 力扣50(java)-Pow(x,n)(中等)

    题目: 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即xn ). 示例 1: 输入:x = 2.00000, n = 10输出:1024.00000示例 2: 输入:x = 2.10 ...

  2. 解密万亿参数M6模型预训练背后的分布式框架Whale

    ​简介: 最近,阿里云PAI团队和达摩院智能计算实验室一起发布"低碳版"巨模型M6,大幅降低万亿参数超大模型训练能耗.借助我们自研的Whale框架仅使用480卡GPU,即训练出了规 ...

  3. dotnet C# 通过 Vortice 将 ID2D1CommandList 作为特效的输入源

    使用 Direct2D 过程中将可以使用到 Direct2D 强大的特效功能,比如给某些界面绘制内容添加特效支持.本文将告诉大家如何通过 Vortice 将 ID2D1CommandList 作为特效 ...

  4. OSI模型之网络层

    一.简介 网络层是OSI参考模型中的第三层,同时也是TCP/IP模型的第二层.它介于传输层和数据链路层之间,主要任务是把分组从源端传到目的端,为分组交换网上的不同主机提供通信服务.网络层传输单位是数据 ...

  5. 理解FPGA内部的同步信号、异步信号和亚稳态

    FPGA(Field-Programmable Gate Array),即现场可编程门阵列.主要是利用内部的可编程逻辑实现设计者想要的功能.FPGA属于数字逻辑芯片,其中也有可能会集成一部分模拟电路的 ...

  6. 如何在M1 MACBOOK上准备好ORB-SLAM2的环境

    1. 环境 M1 Macbook Air Parallels Desktop 17 关于虚拟机,在之前尝试了UTM,但是性能欠佳,卡顿情况比较多,而且未能解决联网问题,最终只能含泪放弃 Paralle ...

  7. 10、操作系统安全加固-Linux加固

    1.账号管理与认证授权 1.1.为不同的管理员分配不同的账号 目的:根据不同用途设置不同账户账号,提高安全层级 实施方法: 1.设置高风险文件为最小权限,如:passwd.shadow.group.s ...

  8. Oracle中ALTER TABLE的五种用法(一)

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...

  9. FE知识点(硕哥)

    目录 前传: 1.typeof和类型转换 正文: 1.作用域.作用域链([[scope]]) 2.立即执行函数 3.闭包 4.对象.包装类 5.原型原型链 6.call.apply 7.继承模式.命名 ...

  10. ollama 源代码中值得阅读的部分

    阅读 Ollama 源代码以了解其内部工作机制.扩展功能或参与贡献,以下是一些值得重点关注的部分: 1. 核心服务模块: 查找负责启动和管理模型服务的主程序或类,这通常是整个项目的核心逻辑所在.关注如 ...