时间:2024-01-26 06:45:01 | 来源:网站运营
时间:2024-01-26 06:45:01 来源:网站运营
React组件可视化拖拽页面搭建,源码生成,你有什么想法?:正好有篇文章可以参考:本文主要内容
draggable="true"
的属性即可,另外,超链接和图像都是默认可拖动的。ondragstart
、ondragenter
、ondragover
、ondragleave
等等各阶段发生在元素上的拖动事件,最后还需要处理ondrop
事件完成最终的放置,我们需要做好数据的传递,可放置区域的识别、最终位置的处理,页面的更新等等一系列细小繁琐的工作。backend
,monitor
,drag
,drop
。import { HTML5Backend } from 'react-dnd-html5-backend'import { DndProvider, useDrag, useDrop } from 'react-dnd'function Drag() { const [collectedProps, drag] = useDrag({ item: { values, type: 'KEY' } }) return ( <div ref={drag}>Drag</div> )}function Drop() { const [collectedProps, drop] = useDrop({ accept: 'KEY' }) return ( <div ref={drop}>Drop Area</div> )}export default function Demo() { return ( <DndProvider backend={HTML5Backend}> <Drag /> <Drop /> </DndProvider> )}
react-dnd-html5-backend
,否则就使用react-dnd-touch-backend
,注意DndProvider
一定是在Drag和Drop的最外层使用的。draggable=true
的属性,同时拖动的所有事件都会被我们监听到。使用方法可以参考上面例子。const [collectedProps, drag] = useDrag({item, canDrag, collect})
useDrag返回的数组一共有三个元素,我们只说前两个:collectedProps: 这其实是React-DnD一个很精妙的设计,组件在拖动的时候,此变量便代表着需要监听的数据drag: 即拖动元素的Ref引用,赋给对应的DOM元素即可
useDrag的函数参数也很多,这里只挑重要的说一下:item: 必填,即包含的数据对象,必须字段type,与drop对象对应,只有同一个type值的才能被放置进去canDrag: 选填,(monitor) => boolean,表示是否可拖拽,这在区分编辑与只读模式非常有用collect: 选填,(monitor) => object,通过此方法返回的值可以从上述的collectedProps中取到, 通过使用monitor判断状态,我们可以返回如opacity、hightlighted等属性用来给拖动元素添加样式
const [collectedProps, drop] = useDrop({ accept, hover, drop, collect })
其中参数和返回值如下:collectedProps: 同上,也是collect函数返回的objectdrop: 即放置元素的Ref引用,赋给对应的DOM元素即可
useDrop的参数也很多,我们也挑重点的说明一下:accept: 必填,支持字符串或者字符串数组,对应于drag的type值,同样的值才可被拖入此元素中hover: 选填,(item, monitor) => void,item即拖动到此drop上drag对象的值,通过用于展示滑上后的预览效果drop: 选填,(item, monitor) => void,同上,此事件在鼠标放开后触发collect: 选填,(monitor) => object,作用同上,也可以用来表达drag进来和离开事件
至此所有的react-dnd基本概念已经介绍完了,正所谓“九层之台起于累土,千里之行始于足下”,页面上的所有交互都是基于这些最基本的功能实现的,也许你仍然觉得很抽象,不妨参考下官网的Demo其中Sandbox的代码例子来学习一下,挤需体验十番钟,里造会干我一样,爱象节款工具!resize
来支持拉伸,比如常见的textarea就是默认内置了此属性,但是浏览器并未像drag一样提供resize专门的API,故大部分库都是通过监听mousedown
,mousemove
,mouseup
这种有些hack的方式完成的。grid
来设置步长,如果要做定制化的对齐就麻烦了,这里分享一个思路,我们可以在onResize或onResizeStop的时候,通过参数我们可以获取偏移位置,此时可以对偏移位置进行计算后四舍五入,便可保证按比例变化。document.elementFromPoint(x,y)
方法,通过不断加步长迭代的方式应该可以找到最近的子元素并获取对应的宽高。TYPE="Container"拖拽源容器即所有可供用户拖拽到画布上的容器布局,所有的组件应当被放置到容器内进行布局上的管理,如果组件能实现良好的布局管理其实也可以不需要此容器。
TYPE="Widget"即实际业务上需要的展示组件,这部分是支持二次开发的,且用了Form-Render 支持以配置项的方式生成组件配置表单,组件只需要关注业务逻辑,配置项会自动注入进来。
TYPE="PaintContainer" ACCEPT=["Container", "PaintContainer"]当把拖拽源拖入画布后,即生成一个画布容器区域,也可以不用一个新的TYPE,这样做主要是便于快速区分是从拖拽源过来的或是画布上模块的移动,如果想让一个DOM同时支持Drag & Drop,可以这样做:
const ref = useRef();const [,drop] = useDrop({});const [,drag] = useDrag({});drop(drag(ref));return <div ref={ref}> Both Can Drag & Drop </div>
TYPE="PaintWidget" ACCEPT=["Widget", "PaintWidget"]这里也可以用两个不同的TYPE来区分,区分从拖拽源进来的还是从画布上别的地方拖进来的,一个是把数据填充进去,一个是交换两个位置的下标。
{ uuid: string; // 唯一标识区块的id width,height... // 定位与尺寸属性 children: { // 里面的子展示组件 uuid: string; // 唯一标识展示组件的id span: number; // 展示组件占宽度 widgetId: string; // 具体是哪一个展示组件,渲染时会取组件列表中获取并渲染 config: object; // 个性化配置项值 }[] }
这里不得不赞美一下React的 Render(data) => View 模式做这种画布实在太合适了,每次只要修改了数据结构,React就会自动根据数据结构渲染出画布里具体的内容,少操了很多心。[ { data: '2020-09-01', type: 'A', count: 5 }, { data: '2020-09-03', type: 'A', count: 15 }, { data: '2020-09-03', type: 'B', count: 10 }, { data: '2020-09-06', type: 'C', count: 20 },]
上面的数据,缺少了9月2日和9月4日,9月5日的数据,如果不把空缺的时间填上去,那横轴间隔就会很奇怪。responseData数组
,总种类数为M,分享一个O(NM)时间复杂度的方法(因为最终数组长度就是N*M,所以应该还是蛮高效的)dayjs工具
生成从查询起始时间到终止时间的时间序列数组dateList
,元素为日期stringresultList
,参考Echarts规范,这个数组的格式为{ type: value[] },type就是状态值,value的下标是日期的下标,值是count数据dateList
第0
个元素,下标指针j指向responseData
第0
个元素resultList[Enum(M)][i]
赋值resultList[Enum(M)][i] || 0
dateList[i]
和responseData[j]
对应的日期是否一样,如果一样,则跳转到第六步,否则到第七步resultList[type][i]
为responseData[j].count
,这里的type是responseData[j].type
,然后j++
,因为还要在结果中找寻同一个日期下其他数据,接着返回第四步i++
,然后返回第四步i
超过dateList
的长度后,终止循环即可关键词: