最近一次团队会议中提到了这个问题,感觉有点意思,就有了以下的思考。
我们可以很轻松的写出以下解决思路:
- 每一项的数据模型都有一个字段
order
,表示排序的依据。 - 拖拽每一项后对
order
字段进行一定的变更,并发送修改请求,持久化排序字段。
问题就在于第二步中的 进行一定的变更,是如何变更?
从这一点入手就出现了各种不同的解决方案。
取前后项差值除以2
这是原来旧项目中采用的方案。
- 每一项数据初始化一个较大的
order
值,如:10000、20000、30000… - 拖拽变化后,取前后项的
order
值相加除以2
。假如把第三行拖拽到第一和第二行之间,那么它的order
值由30000
改为(10000 + 20000) / 2
。
理论上来讲,如果允许存在浮点数且不限制数据精度,绝对是可取的。退一步来说,也可以在数据临界时,或者某个空闲的时候依照当前顺序对数据库中的order
列重新初始化。
这种方案的特点是:新的order
值永远在前后项order
值的区间内。
由这个特点可以衍生出一些方案,比如:降位法。
原始数据:
ID | order |
---|---|
1cE2927ef1C6 | 1 |
8ea5Ed2687A6 | 1.1 |
2c70bADbe43C | 2 |
16DA261B24F1 | 2.1 |
4Da27EE5d3de | 2.2 |
8ea5Ed2687A6 | 2.3 |
65A64F9c12Ae | 3 |
把最后一项放到倒数第二项之前:
ID | order |
---|---|
1cE2927ef1C6 | 1 |
8ea5Ed2687A6 | 1.1 |
2c70bADbe43C | 2 |
16DA261B24F1 | 2.1 |
4Da27EE5d3de | 2.2 |
65A64F9c12Ae | 2.21 |
8ea5Ed2687A6 | 2.3 |
由于2.2
和2.3
在十分位上不存在数的间隔,所以插入到之间的项降一位到百分位上。
取前后项的ID
这是由链表数据结构想到的方案。每一项数据记录前一项或后一项的ID
,拖拽变化后,进行对应的修改。
缺点:
- 数据渲染排序阶段开销大。假如取前一项
ID
为排序依据,需要找到前一项ID为null
的为第一行数据,再找出前一项ID为第一行数据ID的为第二行数据…要深度遍历。 - 前一项或后一项被删除,需要在删除数据的同时对受影响的排序字段进行数据修复,重新关联前一项或后一项的
ID
,至少 2 个请求。