笨办法,直接按照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"]]);
笨办法,直接按照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"]]);
初始化的时候邻近的两个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的时候,就需要重新初始化。局部初始化也可以。
可以调整间距的值,值越大,重新初始化的概率越小。但总数据量也就越小了。
总数据是很多,但是展示到列表应该是分页展示的吧,也就是不管怎么拖动调整顺序,他都应该是在这一页的吧。
说一下我的想法,有可能理解有误,仅供参考:
假设每页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条数据传到后端进行更新
思考了一下,需求之一是局部更新,那么我们就一定不能使用仅仅一个排序列,使用一个排序列在顺序调整时理论上最大可能要更新全表的元素。
我能想到的思路是结合主排序和次要排序, 列表中创建元素时,默认递增主排序。
列表中插入或拖拽数据时,我们把操作的元素和目标元素(拖拽后的前一个元素)归为一组,然后再更新组内的次要排序,我们假定这两个字段为: main_order
和 drag_order
。
需要前端提供操作的元素和目标元素(拖拽后的前一个元素),我们姑且叫它们 id
和 after_id
其实说到这你应该也知道如何做了。
省略四条 SQL, 两条 SELECT 两条 UPDATE。。。
不懂算法, 以仅有的知识面感觉位运算尝尝使用在排序算法中用来节省内存,在本例中,当然也可以使用位运算,对 drag_order
进行 <<
或 >>
操作,但是这样做有一个弊端, bigint 的最大长度是 2 的 64 次方,也就是说 drag_order
只能支持到 64 种排序。我还是偏向于直接 +1 。 如果有懂的或楼主能联系到大佬,还请斧正一下我的理解,多谢
- 排序字段用浮点数
- 初始时用全部用整数位排序
- 每次调整位置时取前后数据的 rank / 2
- 当rank / 2取有效位后等于前一位或者后一位时,根据当前排序全部初始化为整数
缺点:当rank / 2失败时,需要全表初始化排序字段
优点:当rank / 2满足时,更新列数最少
注1: 如果rank / 2失败率够小,那肯定是值得的
注2:整数位和小数位可以替换为纯整数,根据取前几位和后几位来代替,当表比较大时,也可以拆分成两个字段甚至两个以上字段来扩展
推荐文章: