求教列表排序的解决方案(拖拽排序)

如题

如何设计?

  1. mysql 增加单纯 rank 字段
  2. mysql 增加 before after id 的 这种形式
  3. mysql 增加 rank 字段,获取前后数据的 rank / 2 ,这样会由无限小数

如何进行排序

sql 排序,还是查询出来后排序

大佬的建议

听原先公司大佬说可以使用二进制排序,不用更新所有条数。不知道在座的大佬们有没有用过

未知的永远是最精彩的!
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

笨办法,直接按照rank字段越小的越在前,每次拖动之后,把当前拖动id和拖动后一条数据的id都传到后端

$params = [
"change_id" =>10,
"after_id" =>20,
];
//表查询数据
$changeInfo = ["id"=>10,"rank"=>11];
$afterInfo = ["id"=>20,"rank"=>5];

Model::where("rank",">",$afterInfo["rank"]-1)->update(["rank"=>DB::raw("rank+1")]);
Model::where("id",$params["change_id"])->update(["rank"=>$afterInfo["rank"]]);
1年前 评论
看上隔壁小花了啦 (楼主) 1年前
小猪蹄子 (作者) 1年前
看上隔壁小花了啦 (楼主) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
user_wang 1年前
讨论数量: 37

1. 单纯是 rank 字段,还是记录 before after id 的 这种形式

单纯的 rank 字段,值越大 越靠前

2. sql 排序,还是查询出来后排序

sql 排序即可

1年前 评论
看上隔壁小花了啦 (楼主) 1年前
风吹过有夏天的味道 (作者) 1年前
看上隔壁小花了啦 (楼主) 1年前
风吹过有夏天的味道 (作者) 1年前
看上隔壁小花了啦 (楼主) 1年前
风吹过有夏天的味道 (作者) 1年前

笨办法,直接按照rank字段越小的越在前,每次拖动之后,把当前拖动id和拖动后一条数据的id都传到后端

$params = [
"change_id" =>10,
"after_id" =>20,
];
//表查询数据
$changeInfo = ["id"=>10,"rank"=>11];
$afterInfo = ["id"=>20,"rank"=>5];

Model::where("rank",">",$afterInfo["rank"]-1)->update(["rank"=>DB::raw("rank+1")]);
Model::where("id",$params["change_id"])->update(["rank"=>$afterInfo["rank"]]);
1年前 评论
看上隔壁小花了啦 (楼主) 1年前
小猪蹄子 (作者) 1年前
看上隔壁小花了啦 (楼主) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
小猪蹄子 (作者) 1年前
user_wang 1年前

数据能拖拽,那说明单组数据很少。直接rank

1年前 评论

总数据是很多,但是展示到列表应该是分页展示的吧,也就是不管怎么拖动调整顺序,他都应该是在这一页的吧。
说一下我的想法,有可能理解有误,仅供参考:
假设每页5条数据,rank越小越靠前,假设数据是
[{id:6,rank:6},{id:7,rank:7},{id:8,rank:8},{id:9,rank:9},{id:10,rank:10}],假设把id为7的拖到第一个,那数据变成[{id:7,rank:6},{id:6,rank:7},{id:8,rank:8},{id:9,rank:9},{id:10,rank:10}],把这5条数据传到后端进行更新

1年前 评论
看上隔壁小花了啦 (楼主) 1年前
deatil 1年前

加一个 rank_update_at,更新的时候,只需要把这两个 rank_update_at 和 rank 更新就行。取的时候,按照这两个字段排序。

1年前 评论
看上隔壁小花了啦 (楼主) 1年前
看上隔壁小花了啦 (楼主) 1年前
ㅤㅤ (作者) 1年前

初始化的时候邻近的两个rank的差值是20。

另外加一个间距字段,表示当前行和下一行的rank的差值。

比如 ,初始化的时候,行1,0,20;,行2,20,20;,行3,40,20;

行3移动到行1之后就变成,行1,0,10;,行2,20,40;,行3,10,10;

需要改动三行,原来位置的上一位间距增加我现有间距,最新位置的上一行间距减一半,最新位置的rank及间距。

当有间距为1的时候,就需要重新初始化。局部初始化也可以。

可以调整间距的值,值越大,重新初始化的概率越小。但总数据量也就越小了。

1年前 评论

思考了一下,需求之一是局部更新,那么我们就一定不能使用仅仅一个排序列,使用一个排序列在顺序调整时理论上最大可能要更新全表的元素。

我能想到的思路是结合主排序和次要排序, 列表中创建元素时,默认递增主排序。 列表中插入或拖拽数据时,我们把操作的元素和目标元素(拖拽后的前一个元素)归为一组,然后再更新组内的次要排序,我们假定这两个字段为: main_orderdrag_order

需要前端提供操作的元素和目标元素(拖拽后的前一个元素),我们姑且叫它们 idafter_id

其实说到这你应该也知道如何做了。

省略四条 SQL, 两条 SELECT 两条 UPDATE。。。

不懂算法, 以仅有的知识面感觉位运算尝尝使用在排序算法中用来节省内存,在本例中,当然也可以使用位运算,对 drag_order 进行 <<>> 操作,但是这样做有一个弊端, bigint 的最大长度是 2 的 64 次方,也就是说 drag_order 只能支持到 64 种排序。我还是偏向于直接 +1 。 如果有懂的或楼主能联系到大佬,还请斧正一下我的理解,多谢

1年前 评论
看上隔壁小花了啦 (楼主) 1年前

如果没记错的话,自己用二进制排序时对排序的目标有数量限制的,更新时需要更新2条数据,进行位置调换。不知道你说的那个大佬是使用的那种二进制方式,对目标有无数量限制

1年前 评论
看上隔壁小花了啦 (楼主) 1年前
  1. 排序字段用浮点数
  2. 初始时用全部用整数位排序
  3. 每次调整位置时取前后数据的 rank / 2
  4. 当rank / 2取有效位后等于前一位或者后一位时,根据当前排序全部初始化为整数

缺点:当rank / 2失败时,需要全表初始化排序字段

优点:当rank / 2满足时,更新列数最少

注1: 如果rank / 2失败率够小,那肯定是值得的

注2:整数位和小数位可以替换为纯整数,根据取前几位和后几位来代替,当表比较大时,也可以拆分成两个字段甚至两个以上字段来扩展

1年前 评论

这种排序,我建议直接使用,删除整个数据列,无主键的方式,然后以当前前端给的数据来插入,每次拖动都存入最新的全部数据,老旧数据全部丢弃

1年前 评论

我还挺好奇拖拽排序如何适用在有分页的列表,比如把第一页的某一条调整到第二页数据种某一条的后面,这种交互是如何实现的?

1年前 评论
看上隔壁小花了啦 (楼主) 1年前

每一条数据的排序值设置一个较大的间隔,拖动后排序值设置为中间数。配合判断中间数,对排序值进行重置。

A: 0
B: 100
C: 200
D: 300

将 C 拖动到 B 前边:ceil((100-0)/2) = 50

A: 0
C: 50
B: 100
D: 300

当计算出来的数值为连续的时候就需要重置一下排序值。

UPDATE items SET `rank` = `id` * 100 WHERE 1
1年前 评论
JinBB 1年前
看上隔壁小花了啦 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!