为什么拖拽的 api 都很难用?

最终效果

先来看达到了什么样的效果 https://github.com/mulcloud/s...

undo 操作

拖放到区域外自动回滚

Framer Motion 的缺点

拖拽和动画是由 Framer Motion 实现的。Framer Motion 在表达动画方面毫无疑问相当牛逼,一点点的代码,就可以实现非常丰富的效果。比 react-spring 还要强!

Framer Motion 在拖拽方面要差点意思。这个是官方给的例子 https://codesandbox.io/s/framer-motion-2-drag-to-reorder-fc4rt。 主要有两大缺点。

第一个缺点是缺少 drag over 事件。HTML5 的 Drag/drop api 是有两部分的,一部分是被 drag 的元素,一部分是 dragging over 的元素。而 framer motion 仅仅提供了被 drag 元素的 dragStart 和 dragEnd 两个事件。这个就很不符合直觉了,那我被 drag over 了,怎么显示我这里是可以被 drop 的呢?

第二个缺点是实现写得比较绕。第1步先用 ref 拿到了 DOM 元素。第2步,在 useEffect 里采集每个 DOM 元素的位置,复制到另外一个名字叫 positions 的 useRef 上。第3步,假定一个 DOM 元素的数组就是界面上要排序的元素,进行元素位置互换。这相当于是把一部分的 DOM 状态做了一个完整的拷贝,复制到了 react state 里。

为什么 react 拖拽库的 api 都不好用呢?

react dnd 也很难用 https://react-dnd.github.io/react-dnd/about

为啥这些 api 都不做得好用一点呢?我分析有以下原因

  • react 的理念是 ui 由 state 渲染而来。但是拖拽的时候是找不到对应的 react state 的。
  • 直接操作 dom 的拖拽库,例如 https://github.com/SortableJS/Sortable直接把 DOM 当 state 操作。但是这个和 react 渲染的界面又会冲突。需要做一些 hack 的工作才能让这样模式的拖拽库和 react 配合起来。
  • 跨列表拖拽等需求经常需要在多个组件之间移动元素。这个时候是需要全局有 store 的,而不是每个组件各管各的状态。react 社区没有统一的全局 store,所以各个拖拽库只好让你来自己做适配了。
  • 拖拽过程的 placeholder/drop zone/辅助线 等各种交互效果都是有很重的业务逻辑的。这些业务逻辑严重依赖于 xy 坐标进行计算。但是 react 的代码里比较难拿到 DOM 元素,以及 xy 坐标。需要 ref 和 useEffect 这样做一份复制。

直接访问 DOM 就好了嘛

不能理解为啥用了 react,就一定要啥都用 react。毕竟 Web DOM 的 api 还在那里啊,为啥不用呢?拖拽过程中计算元素位置,最方便最直观的,当然是直接用 DOM 的 api 取得鼠标下面的元素,然后访问 offsetLeft / offsetHeight 等元素属性进行计算嘛。Framer Motion 的例子里复制一份有什么必要呢。如果有多个列表要拖拽,难道每个列表都要平行维护一份 DOM 的副本状态在 react state 中么?这也太原教旨主义了。

完全托管状态

这个想法就是用一个“状态管理”工具把所有的组件状态都管理起来。这样就能很方便的实现 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=

原文链接:segmentfault.com

上一篇:React 仿简书项目实战
下一篇:CSS-position

相关推荐

  • 鼠标事件实现拖拽

    为什么需要拖拽 当前的互联网用户早已习惯了拖拽,习惯了拖拽带来的便利。任何一个前端项目都有加入拖拽这个功能的可能性。 拖拽的实现方案 鼠标事件实现 drag and drop api 这两种实现方...

    6 个月前
  • 高阶组件 + New Context API = ?

    1. 前言 继上次小试牛刀(https://github.com/SmallStoneSK/Blog/issues/6)尝到高价组件的甜头之后,现已深陷其中无法自拔。。。

    2 年前
  • 面试!你真的准备好了吗?|手写API系列梳理

    "不畏惧,不讲究,未来的日子好好努力"——大家好!我是小芝麻😄 标题党,它又、又、又来了...... (/public/upload/ce1d43cfb86634a10b9c8a07be33...

    21 天前
  • 面板拖拽之vue自定义指令

    前言 在指令里获取的this并不是vue对象,vnode.context才是vue对象,一般来说,指令最好不要访问vue上的data,以追求解耦,但是可以通过指令传进来的值去访问method或re...

    1 年前
  • 除了composition API,vue3.0文档又带来了什么新东西?

    (/public/upload/bceee5bf249edce49d803dcfff22199b) 异步组件 在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器...

    13 天前
  • 重构 - 设计API的扩展机制

    1.前言 上篇文章,主要介绍了重构的一些概念和一些简单的实例。这一次,详细的说下项目中的一个重构场景给API设计扩展机制。目的就是为了方便以后能灵活应对需求的改变。

    2 年前
  • 重新开坑,在 react 中使用 composition API

    emmm大家好,那个,虽然最近新型肺炎,搞的人心惶惶,没啥动力写码 其实我也没啥可写的了,但是闲着也是闲着,然后记起来 smox 弃坑了还有一堆星星,想着怎么重新开坑 背景 smox 弃坑,不是我任性...

    6 个月前
  • 轻松实现拖拽和预投影(附demo代码)

    感觉放弃csdn了,于是同样的内容搬迁到掘金上~~~也不是别的,我就是感觉csdn上放放问题就好了,有意思的小分享还是得掘金~(这绝不是舔,绝不是!!!) 这次的需求呢,听起来比较正常,指定目标区域的...

    2 个月前
  • 足球特殊指数api接口示例

    分享下足球特殊指数数据,单双、总进球数、半全场赔率api接口示例,详情查看在线文档(https://www.shenlu88.com/doc.html) 接口返回的是Json数据,可以使用fastjs...

    8 个月前
  • 足球冠军指数 api接口示例

    分享下足球冠军指数API数据,接口示例如下,可查看在线文档(https://www.shenlu88.com/doc.... 接口返回的是Json数据,可以使用fastjson来解析 API...

    5 个月前

官方社区

扫码加入 JavaScript 社区