先來看達到了什麼樣的效果 https://github.com/mulcloud/s...前端
undo 操做react
拖放到區域外自動回滾git
拖拽和動畫是由 Framer Motion 實現的。Framer Motion 在表達動畫方面毫無疑問至關牛逼,一點點的代碼,就能夠實現很是豐富的效果。比 react-spring 還要強!github
Framer Motion 在拖拽方面要差點意思。這個是官方給的例子 https://codesandbox.io/s/framer-motion-2-drag-to-reorder-fc4rt 。 主要有兩大缺點。spring
第一個缺點是缺乏 drag over 事件。HTML5 的 Drag/drop api 是有兩部分的,一部分是被 drag 的元素,一部分是 dragging over 的元素。而 framer motion 僅僅提供了被 drag 元素的 dragStart 和 dragEnd 兩個事件。這個就很不符合直覺了,那我被 drag over 了,怎麼顯示我這裏是能夠被 drop 的呢?redux
第二個缺點是實現寫得比較繞。第1步先用 ref 拿到了 DOM 元素。第2步,在 useEffect 裏採集每一個 DOM 元素的位置,複製到另一個名字叫 positions 的 useRef 上。第3步,假定一個 DOM 元素的數組就是界面上要排序的元素,進行元素位置互換。這至關因而把一部分的 DOM 狀態作了一個完整的拷貝,複製到了 react state 裏。api
react dnd 也很難用 https://react-dnd.github.io/react-dnd/about數組
爲啥這些 api 都不作得好用一點呢?我分析有如下緣由dom
不能理解爲啥用了 react,就必定要啥都用 react。畢竟 Web DOM 的 api 還在那裏啊,爲啥不用呢?拖拽過程當中計算元素位置,最方便最直觀的,固然是直接用 DOM 的 api 取得鼠標下面的元素,而後訪問 offsetLeft / offsetHeight 等元素屬性進行計算嘛。Framer Motion 的例子裏複製一份有什麼必要呢。若是有多個列表要拖拽,難道每一個列表都要平行維護一份 DOM 的副本狀態在 react state 中麼?這也太原教旨主義了。ide
這個想法就是用一個「狀態管理」工具把全部的組件狀態都管理起來。這樣就能很方便的實現 undo/redo 了。固然你會說,redux 就是這樣的狀態管理工具。
並且咱們但願是多 store 的狀態管理,對應到每一個可被 draggable 和 droppable 的 DOM 都有一個 store。這個用 redux 就不那麼直接了。爲何有多 store 的需求呢?由於前面直接訪問 DOM 作了排版上的計算,而後第二步就是要更新 state 觸發重渲染了。咱們須要從 DOM 元素找到對應的 store,dispatch action 更新這個 store。一個直觀的作法就是在 DOM 元素上加上 data-model-class 和 data-model-id 的屬性,拿這兩個屬性去找到對應的 store。
最終實現的代碼在這裏 https://github.com/mulcloud/state-management-demo/tree/master/src/Scenario6
工做地點:北京 / 杭州
很是有創新性和成長的工做內容 https://www.zhipin.com/job_detail/?query=%E4%B9%98%E6%B3%95%E4%BA%91&city=101010100&industry=&position=