最近在做拖拽排序和看板功能,刚好涉及到拖拽排序位置如何保存后端的问题。我也顺便调研了一下,简单说下一些做法。
全量更新
一开始我想到的暴力解法是每次排序将所有数据的排序都改一遍,比如下面的例子。
[{ index: 1, id: 100 }, { index: 2, id:303 }, { index: 3, id:237 }]
// ===>
[{ index: 1, id:303 }, { index: 2, id: 100 }, { index: 3, id:237 }]
这种方式如果数据少还可以,但是数据量一大,接口数据的传输以及大数据的处理必然会是个问题。
取中值法
这是网上看到的一个方法,为数组所有元素加上索引值。
当拖拽改变元素位置时,更新 pos。更新规则如下:
- 调整一个元素到两个元素中间时,(pre_item.pos + after_item.pos)/ 2 = pos
- 调整一个元素到第一个元素时, old_first_item.pos / 2 = pos
- 调整一个元素到最后一个元素时, old_last_item.post + 65536 = pos
这种方式会极大地节省接口数据传输的问题。当然也会有一些小问题,比如中间值不是整数;比如第一个元素的索引值已经变为 0;这些问题是需要后端设计策略解决的。
单列偏移法
给数组一个从 0 开始递增的索引值 index,当拖拽移动元素后,将拖拽元素之前的和现在的位置传递给后端,后端通过两个索引值更新整个数组的 index 索引值,与前端保持同步。
[ 0, 1, 2, 3, 4, 5 ]
// 移动 index=2 的元素
[ 0, 1, 3, 4, 2, 5 ]
// 传给后端 { oldPos: 2, currentPos: 4 }
// 后端移动数组数据,并更新整个数组的 index 为
[ 0, 1, 2, 3, 4, 5 ] // 又变回了递增 index
这样就能和前端遍历时的索引值对应上,做到前端移动元素,后端同步排序的功能。
交给后端算偏移值
这个方式类似于取中值法:首先为所有元素定义六位数的索引值。当拖拽移动元素后,将拖拽元素放置位置前后的元素索引值传给后端,后端去进行索引值的计算。并通过接口响应返回新的索引值更新到前端。
我认为它和取中值的区别就在于一个是前端算完直接给后端,一个是后端进行计算。其实差不多吧。
关于看板的排序问题
如果是列表排序是单列的问题,那么看板的排序就是多列排序和移动的问题。我的想法是,把多列当做一列来看。排序索引上从第一列自上而下递增,然后是后续几列。
而如何跨列移动,其实就是在做拖拽排序的时候更改一下元素所在列的状态,可能是一个状态,也可能是一个 ID,其实就是比单列排序多传了一个字段而已。