把拖动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;

react中实现可拖动div的更多相关文章

  1. 理解React中es6方法创建组件的this

    首发于:https://mingjiezhang.github.io/(转载请说明此出处). 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的 ...

  2. React中props.children和React.Children的区别

    在React中,当涉及组件嵌套,在父组件中使用props.children把所有子组件显示出来.如下: function ParentComponent(props){ return ( <di ...

  3. react中createFactory, createClass, createElement分别在什么场景下使用,为什么要这么定义?

    作者:元彦链接:https://www.zhihu.com/question/27602269/answer/40168594来源:知乎著作权归作者所有,转载请联系作者获得授权. 三者用途稍有不同,按 ...

  4. React中父组件与子组件之间的数据传递和标准化的思考

    React中父组件与子组件之间的数据传递的的实现大家都可以轻易做到,但对比很多人的实现方法,总是会有或多或少的差异.在一个团队中,这种实现的差异体现了每个人各自的理解的不同,但是反过来思考,一个团队用 ...

  5. React中使用CSSTransitionGroup插件实现轮播图

    动画效果,是一个页面上必不可少的功能,学习一个新的东西,当然就要学习,如何用新的东西,用它的方法去实现以前的东西啦.今天呢,我就在这里介绍一个试用react-addons-css-transition ...

  6. React中的路由系统

    React中的路由系统 提起路由,首先想到的就是 ASPNET MVC 里面的路由系统--通过事先定义一组路由规则,程序运行时就能自动根据我们输入的URL来返回相对应的页面.前端中的路由与之类似,前端 ...

  7. 关于React中状态保存的研究

    在使用react搭配react-router做应用的时候,你可能遇到这样的问题,当我从第一个页面过渡到第二个页面,然后返回之后,发现之前的页面的状态全部不见了,即回到了初始的状态. 这点在页面存在多个 ...

  8. React 深入系列1:React 中的元素、组件、实例和节点

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...

  9. React 中阻止事件冒泡的问题

    在正式开始前,先来看看 JS 中事件的触发与事件处理器的执行. JS 中事件的监听与处理 事件捕获与冒泡 DOM 事件会先后经历 捕获 与 冒泡 两个阶段.捕获即事件沿着 DOM 树由上往下传递,到达 ...

随机推荐

  1. Ubuntu U盘启动出现“Failed to load ldlinux.c32”解决

    最后用ultraISO软碟通,刻录映像时写入方式选择”RAW”,成功解决!!!

  2. Asp.Net Core入门之静态文件

    静态文件(css,js,html等类型文件)通常位于 web根目录下,而ASP.Net Core框架默认内容根目录下的wwwroot文件夹为web根目录.这里简单解释下内容根目录:实际就是指包含可执行 ...

  3. 在Java虚拟机上班是一种怎样的体验?

    228 人赞同了该回答 利益相关,匿了! JVM公司里面线程众多,派系林立,尤其是执行引擎那波人,因为是核心部门,经常diss别的部门. 428 人赞同了该回答 不请自来. 其实在JVM工作没有你们想 ...

  4. 程序员Linux教程初窥入门-刘志敏-专题视频课程

    程序员Linux教程初窥入门-313人已学习 课程介绍        程序员Linux教程初窥入门主要针对初级入门程序员的课程,也是为后期学习其他课程的一个基础,Git.Maven.Jenkins.R ...

  5. junit基本介绍视频笔记1

    程序员每天工作的基本流程: 1.从svn检出代码: 2.运行单元测试,测试无误,进入下一步: 3.开始一天的代码编写工作: 4.代码提交到服务器之前进行单元测试: 5.单元测试通过提交到svn服务器. ...

  6. Python 简明教程 --- 16,Python 高阶函数

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 对于那些快速算法,我们总是可以拿一些速度差不多但是更容易理解的算法来替代它们. -- Douglas ...

  7. 硬件对同步的支持-TAS和CAS指令

    目录 Test and Set Compare and Swap 使用CAS实现线程安全的数据结构. 现在主流的多处理器架构都在硬件水平上提供了对并发同步的支持. 今天我们讨论两个很重要的硬件同步指令 ...

  8. mac下创建安卓应用 hello-world

    教程 https://www.jianshu.com/p/bf77cb5ce70b 需要注意的地方 jdk目录查找 jdk目录拷贝到tool目录下面(jdk可以拷贝,没有其他牵扯) https://w ...

  9. [区间+线性dp]数字游戏

    题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共\(n\)个),你要按顺 ...

  10. Kubernetes 两步验证 - 使用 Serverless 实现动态准入控制

    作者:CODING - 王炜 1. 背景 如果对 Kubernetes 集群安全特别关注,那么我们可能想要实现这些需求: 如何实现 Kubernetes 集群的两步验证,除了集群凭据,还需要提供一次性 ...