如何编写复杂拖拽组件🐣
阅读本文🦀
1.您将了解到如何让echart做到响应式
2.您将到如何编写复杂的拖拽组件
3.和我一起实现可拖拽组件的增删改查、可编辑、可以拖拽、可排序、可持久化
4.和我一起实现可拖拽组件的删除抖动动画
前言🌵
在业务中得到一个很复杂的需求,需要实现组件中展示ecahrts图表,并且图表可编辑,可排序,大小可调整,还要可持续化,下面就是解决方案啦
正文 🦁
先看效果再一步步实现
技术调研
如何做到可拖拽?自己造轮子?显然不是,当然是站在巨人的肩膀上😁
- react-dnd
- 文档齐全
- github star星数16.4k
- 维护更新良好,最近一月内有更新维护
- 学习成本较高
- 功能中等
- 移动端兼容情况,良好
- 示例数量中等
- 概念较多,使用复杂
- 组件间能解耦
- react-beautiful-dnd
- 文档齐全
- github star星数24.8k
- 维护更新良好,最近三月内有更新维护
- 学习成本较高
- 使用易度中等
- 功能丰富
- 移动端兼容情况,优秀
- 示例数量丰富
- 是为垂直和水平列表专门构建的更高级别的抽象,没有提供 react-dnd 提供的广泛功能
- 外观漂亮,可访问性好,物理感知让人感觉更真实的在移动物体
- 开发理念上是拖拽,不支持copy/clone
- dnd-kit
- 文档齐全
- github star星数2.8k
- 维护更新良好,最近一月内有更新维护
- 学习成本中等
- 使用易度中等
- 功能中等
- 移动端兼容情况,中等
- 示例数量丰富
- 未看到copy/clone
- react-sortable-hoc
- 文档较少
- github star星数9.5k
- 维护更新良好,最近三月内有更新维护
- 学习成本较低
- 使用易度较低
- 功能简单
- 移动端兼容情况,中等
- 示例数量中等
- 不支持拖拽到另一个容器中
- 未看到copy/clone
- 主要集中于排序功能,其余拖拽功能不丰富
- react-grid-layout
- 文档较少
- github star 星星15.8k
- 维护更新比较好,近三个月有更新维护
- 学习成本比较高
- 功能复杂
- 支持拖拽、放大缩小
总结:为了实现我们想要的功能,最终选择react-grid-layout,应为我们想要的就是在网格中实现拖拽、放大缩小、排序等功能
Coding🔥
由于代码量比较大,只讲述一些核心的code
1.先创建基础布局
- isDraggable 控制是否可拖拽
- isResizable 控制是否可放大缩小
- rowHeight控制基础行高
- layout控制当前gird画布中每个元素的排列顺序
- onLayoutChange 当布局发生改变后的回调函数
<ReactGridLayout
isDraggable={edit}
isResizable={edit}
rowHeight={250}
layout={transformLayouts}
onLayoutChange={onLayoutChange}
cols={COLS}
>
{layouts && layouts.map((layout, i) => {
if (!chartList?.some(chartId => chartId === layout.i))
return null
return (<div
key={layout.i}
data-grid={layout}
css={css`width: 100%;
height: 100%`}
>
<Chart
setSpinning={setSpinning}
updateChartList={updateChartList}
edit={edit}
key={layout.i}
chartList={chartList}
chartId={Number(layout.i)}
scenarioId={scenarioId}/>
</div>
)
})}
</ReactGridLayout>
2.如何让grid中的每个echarts图表随着外层item的放大缩小而改变
const resizeObserver = new ResizeObserver((entries) => {
myChart?.resize()//当dom发生大小改变就重置echart大小
})
resizeObserver.observe(chartContainer.current)//通过resizeObserver观察echart对应的item实例对象
3.如何实现排序的持久化
//通过一下代码可以实现记录edit变量的前后状态
const [edit, setEdit] = useState(false)
const prevEdit = useRef(false)
useEffect(() => {
prevEdit.current = edit
})
//通过将grid中的每个item的排序位置记录为对象,然后对每个属性进行前后的对比,如果没有改变就不进行任何操作,如果发生了改变就可以
//通过网络IO更新grid中item的位置
useEffect(() => {
if (prevEdit && !edit) {
// 对比前后的layout做diff 判断是否需要更新位置
const diffResult = layouts?.every((layout) => {
const changedLayout = changedLayouts.find((changedLayout) => {
// eslint-disable-next-line eqeqeq
return changedLayout.i == layout.i
})
return changedLayout?.w === layout.w
&& changedLayout?.h === layout.h
&& changedLayout?.x === layout.x
&& changedLayout?.y === layout.y
})
// diffResult为false 证明发生了改变
if (!diffResult) {
//这里就可以做图表发生改变后的操作
//xxxxx
}
}, [edit])
4.如何实现编辑时的抖动动画
.wobble-hor-bottom{
animation:wobble-hor-bottom infinite 1.5s ;
}
@-webkit-keyframes wobble-hor-bottom {
0%,
100% {
-webkit-transform: translateX(0%);
transform: translateX(0%);
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
15% {
-webkit-transform: translateX(-10px) rotate(-1deg);
transform: translateX(-10px) rotate(-1deg);
}
30% {
-webkit-transform: translateX(5px) rotate(1deg);
transform: translateX(5px) rotate(1deg);
}
45% {
-webkit-transform: translateX(-5px) rotate(-0.6deg);
transform: translateX(-5px) rotate(-0.6deg);
}
60% {
-webkit-transform: translateX(3px) rotate(0.4deg);
transform: translateX(3px) rotate(0.4deg);
}
75% {
-webkit-transform: translateX(-2px) rotate(-0.2deg);
transform: translateX(-2px) rotate(-0.2deg);
}
}
总结 🍁
本文大致讲解了下如何使用react-grid-layout
如何与echart
图表结合使用,来完成复杂的拖拽、排序、等功能,但是这个组件实现细节还有很多,本文只能提供一个大值的思路,还是希望能够帮助到大家,给大家提供一个思路,欢迎留言和我讨论,如果你有什么更好的办法实现类似的功能
结束语 🌞
那么我的如何编写复杂拖拽组件🐣
就结束了,文章的目的其实很简单,就是对日常工作的总结和输出
,输出一些觉得对大家有用的东西,菜不菜不重要,但是热爱🔥,希望大家能够喜欢我的文章,我真的很用心在写,也希望通过文章认识更多志同道合的朋友,如果你也喜欢折腾
,欢迎加我好友
,一起沙雕
,一起进步
。