拖拽排序后端設計與實現

背景

最近在做課程后臺開發(fā)時抠藕,遇到一個很有意思的問題饿肺。問題是這樣的,有多節(jié)課程盾似,運營人員可以根據需要調整課程的先后順序敬辣,從而更改課程的展示順序。

接到這個需求零院,立刻就想到了以前做首頁banner輪播圖的管理后臺溉跃。輪播圖中每一張圖有先后順序之分,為了進行圖片排序告抄,在設計banner實體時撰茎,設計了一個 weight (權重)字段。然后打洼,讓運營人員給每張圖填寫1~500值龄糊,值越大,則排序越靠前拟蜻。由于輪播圖展示的圖片有限(不超過5張)绎签,即使通過人工填值的方式管理順序,也不是很麻煩酝锅。但是诡必,這種填權重管理順序的方式不適用于數據量較多的課程管理。那么搔扁,如何解決這種排序問題呢爸舒?

為了解決元素自定義排序問題,我們想了很多解決辦法稿蹲。例如扭勉,

  • 增加上移/下移功能,更改當前元素排序
  • 填權重苛聘,或增減權重值
  • 置頂排序
  • 拖拽排序

最后涂炎,綜合考慮了一下忠聚,認為第四種最符合日常操作的習慣。針對拖拽排序進行了后端方案設計唱捣。

image

需求描述

  • 允許更改元素的排序两蟀;
  • 允許新增數據,并更新現有排序震缭;
  • 允許刪除數據赂毯,并更新現有排序。

解決辦法

方法一 全量更新元素位置法

適用場景:排序元素數量較少

原理:每個元素擁有一個字段拣宰,表示元素當前排序的位置党涕。通過前端排序,將排好的元素位置巡社,一次性發(fā)送到后端膛堤。然后,后端統一更新所有元素的位置重贺。

具體實現

實體設計:增加排序字段 sort骑祟,表示元素當前的位置。例如气笙,sort = 1次企,則表示元素處于第一位。

接口設計:

// 排序接口
POST /courses/sorting

// 格式:JSON
// 數組中為元素的ID
// 元素在數組中的序號潜圃,表示了元素的位置
// 例如缸棵,ID為3的元素,排序為 1谭期,ID為2的元素堵第,排序為2
[3, 2, 4, 1]

前端邏輯:當前端排序后,或刪除元素后隧出,將剩余元素ID踏志,以數組的形式發(fā)送給后端。數組的索引序號胀瞪,則表示元素當前的排序针余。

后端實現邏輯:

  • 刪除不存在前端數組中的ID。將前端 ids凄诞,與服務器端的 ids 進行對比圆雁。刪除服務器端存在但前端不存在的 ids
  • 按照數組的排序帆谍,更新所有元素排序伪朽。

總結,此方法僅適用于排序元素較少(例如汛蝙,總元素為5~15個)的場景烈涮。對于大量數據排序并不適用朴肺,適合首頁輪播圖管理、任務卡片管理跃脊。leangoo 的看板卡片管理就是采用這種方式宇挫。

方法二 取中值法(推薦)

原理與實現步驟:

  1. 創(chuàng)建元素時給元素賦默認位置(pos字段記錄該值)。賦值規(guī)則為酪术,當創(chuàng)建第一個元素時,默認位置賦值為65536翠储,第二個元素為 2 * 65536 = 13172绘雁,增加第N個元素時,位置賦值為N*65536援所。
  2. 當拖拽改變元素位置時庐舟,更新 pos。更新規(guī)則如下:
  • 調整一個元素到兩個元素中間時住拭,(pre_item.pos + after_item.pos)/ 2 = pos
  • 調整一個元素到第一個元素時挪略, old_first_item.pos / 2 = pos
  • 調整一個元素到最后一個元素時, old_last_item.post + 65536 = pos
  1. 當前后兩個元素的數值滔岳,不滿足整數時杠娱,更新所有元素的排序。依次給每個元素的 pos賦新值谱煤。例如摊求,第一位賦值65536,第二位為2 * 65536刘离,第N位賦值N*65536室叉。

通過取中值的方法,改變元素的位置硫惕。當需要按序獲取時茧痕,只需要對 pos進行排序,就可以獲取元素的位置恼除。

關于中值重排的問題踪旷,解決方法有多種。例如缚柳,我們可以使用浮點數儲存 pos埃脏,但是需要考慮數據庫存儲的精度問題。而且秋忙,數值過小彩掐,會在前端丟失精度,元素排序會出現問題灰追。當然堵幽,如果在接口層狗超,當檢測到中值過小,則對所有元素進行重排朴下,接口相應速度會存在問題(如果是后端管理系統就不用考慮性能問題了)努咐。

有人提出,利用定時任務每天對所有元素定時重排殴胧,來解決單次接口的性能問題渗稍。個人覺得這個方法,還是存在問題团滥。若定時任務不及時竿屹,那么排序由于精度問題,發(fā)生了排序錯亂的問題灸姊。那么拱燃,定時重排已經無意義。

方法三 單表單列

每個元素力惯,都有一個字段index碗誉,表示元素的排序信息。
規(guī)定元素從0開始遞增父晶。
基本操作如下:

  • 增加數據哮缺。 新增元素時,序號為當前元素數據總量值诱建。
  • 刪除元素蝴蜓。刪除元素時,將大于該元素的序號俺猿,都減1茎匠。
  • 修改元素排序。當元素從 x 移動到 y 時押袍,
    • 若 x < y 時诵冒,則將(x, y)范圍內的元素都減1
    • 若 x > y 時,則將(y, x)范圍內的元素都加1
  • 查詢元素谊惭。展示列表時汽馋,按照 index 字段進行排序即可。若需要查第n位元素時圈盔,元素位置為 index = n - 1豹芯。

這種方式優(yōu)點是,查詢快驱敲,修改慢铁蹈。而且,修改接口的邏輯較重众眨,處理起來比較麻煩握牧。我們很多項目都是采用這種模式容诬。在接口設計方面,我們讓前端傳給后端是一個偏移值(offset)沿腰,offset = y - x览徒。當元素向排序大的方向移動時,offset的為正值颂龙;若往排序小的方向移動時习蓬,offset`為負值。

總結

在選擇具體方案時措嵌,還需要根據具體的業(yè)務場景選擇友雳。方案的選擇規(guī)則總結如下:

  • 若排序元素較少,采用方案一铅匹;
  • 若排序移動次數不是非常頻繁且對接口性能要求高,建議采用方案二饺藤;
  • 若排序移動非常頻繁且接口性能要求不高包斑,可以采用方案三。
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末涕俗,一起剝皮案震驚了整個濱河市罗丰,隨后出現的幾起案子,更是在濱河造成了極大的恐慌再姑,老刑警劉巖萌抵,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異元镀,居然都是意外死亡绍填,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門栖疑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讨永,“玉大人,你說我怎么就攤上這事遇革∏淠郑” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵萝快,是天一觀的道長锻霎。 經常有香客問我,道長揪漩,這世上最難降的妖魔是什么旋恼? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮氢拥,結果婚禮上蚌铜,老公的妹妹穿的比我還像新娘锨侯。我一直安慰自己,他們只是感情好冬殃,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布囚痴。 她就那樣靜靜地躺著,像睡著了一般审葬。 火紅的嫁衣襯著肌膚如雪深滚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天涣觉,我揣著相機與錄音痴荐,去河邊找鬼。 笑死官册,一個胖子當著我的面吹牛生兆,可吹牛的內容都是我干的。 我是一名探鬼主播膝宁,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼鸦难,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了员淫?” 一聲冷哼從身側響起合蔽,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎介返,沒想到半個月后拴事,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡圣蝎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年刃宵,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捅彻。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡组去,死狀恐怖,靈堂內的尸體忽然破棺而出步淹,到底是詐尸還是另有隱情从隆,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布缭裆,位于F島的核電站键闺,受9級特大地震影響,放射性物質發(fā)生泄漏澈驼。R本人自食惡果不足惜辛燥,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挎塌,春花似錦徘六、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嘴高,卻和暖如春竿音,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拴驮。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工春瞬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人套啤。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓宽气,卻偏偏與公主長得像,于是被迫代替她去往敵國和親潜沦。 傳聞我的和親對象是個殘疾皇子抹竹,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內容