动图演示:

背景:

一开始做功能的时候没有增加排序的索引(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. 使用 Docker 部署 TailChat 开源即时通讯平台

    1)介绍 TailChat 官网: https://tailchat.msgbyte.com/ 作者:https://www.moonrailgun.com/about/ GitHub : https ...

  2. 力扣614(MySQL)-二级关注者(中等)

    题目: 在 facebook 中,表 follow 会有 2 个字段: followee, follower ,分别表示被关注者和关注者. 请写一个 sql 查询语句,对每一个关注者,查询关注他的关注 ...

  3. OpenSergo 流量路由:从场景到标准化的探索

    简介: 本文我们将从流量路由这个场景入手,从常见的微服务治理场景出发.先是根据流量路由的实践设计流量路由的 Spec,同时在 Spring Cloud Alibaba 中实践遵循 OpenSergo ...

  4. 从操作系统层面分析Java IO演进之路

    简介: 本文从操作系统实际调用角度(以CentOS Linux release 7.5操作系统为示例),力求追根溯源看IO的每一步操作到底发生了什么. 作者 | 道坚来源 | 阿里技术公众号 前言 本 ...

  5. WPF 将 StaticResource 和 ResourceDictionary 放在一起的魔幻行为

    本文将记录一些在 WPF 里面,使用 StaticResource 将 ResourceDictionary 玩坏的做法.大家可以放心的是,这些玩法基本只有高级玩家或逗比开发者才会使用到 后加入的资源 ...

  6. 2019-11-29-dotnet-remoting-使用事件

    title author date CreateTime categories dotnet remoting 使用事件 lindexi 2019-11-29 10:20:1 +0800 2018-2 ...

  7. VSCode 在 windows 下默认添加 _WIN32 的问题

    现象 在 VSCode 在 windows 下环境中使用时,会默认添加 _WIN32 ,会出现查看代码时,出现错误提示,现象如下 检测到 #include 错误.请更新 includePath.已为此 ...

  8. 局域网内一部分网络设备无法ping通,icmp_seq=1 目标主机不可达

    问题: 来自 192.168.2.99 icmp_seq=1 目标主机不可达.   最近想在局域网内搭建一台服务器,打开SSH服务后发现局域网内的一部分设备无法使用,尝试了各种办法都没能解决,重装系统 ...

  9. STM32F10x 串口使用DMA

    一.DMA简介 DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载.否则,CPU 需要 ...

  10. VUE知识体系、VUE面试题

    1. computed(计算属性)和方法有什么区别? 计算属性本质上是包含 getter 和 setter 的方法 当获取计算属性时,实际上是在调用计算属性的 getter 方法.vue 会收集计算属 ...