react中实现可拖动div
程序员文章站
2022-09-03 21:22:48
把拖动div功能用react封装成class,在页面直接引入该class即可使用。 title为可拖动区域。panel为要实现拖动的容器。 优化了拖动框超出页面范围的情况,也优化了拖动太快时鼠标超出可拖动区域的情况,优化了拖动会卡顿的情况。 页面中添加引入方法:
把拖动div功能用react封装成class,在页面直接引入该class即可使用。
title为可拖动区域。panel为要实现拖动的容器。
优化了拖动框超出页面范围的情况,也优化了拖动太快时鼠标超出可拖动区域的情况,优化了拖动会卡顿的情况。
页面中添加引入方法:
<draggable panelid="要拖动容器的id" titleid="容器内标题的id" contentid="容器内除标题外的其他部分id" setpanelposition={this.setpanelposition.bind(this)}/>
页面中添加拖拽回调函数
//推拽回调函数 setpanelposition(left,top){ this.setstate({pagex: left, pagey: top}) }
要拖动的div如下:
<div id="要拖动的id" style={{left:this.state.pagex,top:this.state.pagey}}></div>
封装的class代码:
import react from 'react'; class draggable extends react.component { constructor(props) { super(props); this.state = { }; } //拖拽 initdrag(){ let {panelid,titleid,contentid} = this.props; this.paneldom = document.getelementbyid(panelid); this.titledom = document.getelementbyid(titleid); this.contentdom = document.getelementbyid(contentid); this.backgrounddom = document.body; this.bindevent(); } //region event componentdidmount() { this.initdrag(); } bindevent(){ this.titledom.onmousedown = this.onmousedown.bind(this); this.titledom.onmouseup = this.onmouseup.bind(this); this.titledom.onmousemove = this.onmousemove.bind(this); this.contentdom.onmouseup = this.oncontentmouseup.bind(this); this.contentdom.onmousemove = this.oncontentmousemove.bind(this); this.backgrounddom.onmouseup = this.onbackgroundmouseup.bind(this); this.backgrounddom.onmousemove = this.onbackgroundmousemove.bind(this); let step = ()=>{ this.activeanimation = true; window.requestanimationframe(step); }; window.requestanimationframe(step); } /** * 鼠标按下,设置modal状态为可移动,并注册鼠标移动事件 * 计算鼠标按下时,指针所在位置与modal位置以及两者的差值 **/ onmousedown (e) { const position = this.getposition(e) this.setstate({moving: true, diffx: position.diffx, diffy: position.diffy}) } // 松开鼠标,设置modal状态为不可移动 onmouseup (e) { const { moving } = this.state moving && this.setstate({moving: false}); } // 鼠标移动重新设置modal的位置 onmousemove (e) { const {moving, diffx, diffy} = this.state if (moving) { if(this.activeanimation){ // 获取鼠标位置数据 const position = this.getposition(e) // 计算modal应该随鼠标移动到的坐标 const x = position.mousex - diffx const y = position.mousey - diffy // 窗口大小,结构限制,需要做调整,减去侧边栏宽度 const { clientwidth, clientheight } = document.documentelement const modal = this.paneldom if (modal) { // 计算modal坐标的最大值 const maxheight = clientheight - modal.offsetheight const maxwidth = clientwidth - modal.offsetwidth // 判断得出modal的最终位置,不得超出浏览器可见窗口 const left = x > 0 ? (x < maxwidth ? x : maxwidth) : 0 const top = y > 0 ? (y < maxheight ? y : maxheight) : 0 if(this.props.setpanelposition){ this.props.setpanelposition(left,top); } } this.activeanimation = false; } } } oncontentmousemove(e){ let obj = {}; obj.target = this.titledom; obj.pagex = e.pagex; obj.screeny = e.screeny; this.onmousemove(obj); } oncontentmouseup(){ this.onmouseup(); } onbackgroundmousemove(e){ let obj = {}; obj.target = this.titledom; obj.pagex = e.pagex; obj.screeny = e.screeny; this.onmousemove(obj); } onbackgroundmouseup(){ this.onmouseup(); } //endregion //region request // 获取鼠标点击title时的坐标、title的坐标以及两者的位移 getposition (e) { // 标题dom元素titledom const titledom = e.target // titledom的坐标(视窗) const x = titledom.getboundingclientrect().left // 由于y轴出现滚动条,需要与鼠标保持一致,存储页面相对位置 const y = this.paneldom.offsettop // 鼠标点击的坐标(页面) let mousex = e.pagex let mousey = e.screeny // 鼠标点击位置与modal的位移 const diffx = mousex - x const diffy = mousey - y return {x, y, mousex, mousey, diffx, diffy} } //endregion //region render //endregion //region clear //endregion render() { return ( <> </> ); } } export default draggable;