React拖拽调整大小的组件
更新时间:2022年8月25日 22:14 点击:906 作者:微笑码客
本文实例为大家分享了React拖拽调整大小的组件,供大家参考,具体内容如下
一、实现流程
1.使用React.cloneElement
加强包裹组件,在包裹的组件设置绝对定位,并在组件内加上四个可调整大小的拖动条,在点击拖动条并进行拖动时会改变DragBox的大小,如下:
2.使用:
<DragBox dragAble={true} minWidth={350} minHeight={184} edgeDistance={[10, 10, 10, 10]} dragCallback={this.dragCallback} > {/* 使用DragBox拖动组件包裹需要调整大小的盒子 */} <div style={{ top: 100 + 'px', left: 100 + 'px', width: 350, height: 184, backgroundColor: "white" }}> <div style={{ backgroundColor: "yellow", width: "100%", height: 30 }}></div> <div style={{ backgroundColor: "green", width: "100%", height: 30 }}></div> <div style={{ backgroundColor: "blue", width: "100%", height: 30 }}></div> </div> </DragBox>
二、代码
DragBox组件
import React, { Component, Fragment } from 'react'; import styles from "./DragBox.less"; /** * 拖拽的公共组件 * 接收参数: * dragAble:是否开启拖拽 * minWidth:最小调整宽度 * minHeight:最小调整高度 * edgeDistance:数组,拖拽盒子里浏览器上下左右边缘的距离,如果小于这个距离就不会再进行调整宽高 * dragCallback:拖拽回调 * * 使用: * 在DragBox组件放需要实现拖拽的div,DragBox组件内会设置position:absolute(React.cloneElement) */ class DragBox extends Component { constructor(props) { super(props); // 父组件盒子 this.containerRef = React.createRef(); // 是否开启尺寸修改 this.reSizeAble = false; // 鼠标按下时的坐标,并在修改尺寸时保存上一个鼠标的位置 this.clientX, this.clientY; // 鼠标按下时的位置,使用n、s、w、e表示 this.direction = ""; // 拖拽盒子里浏览器上下左右边缘的距离,如果小于这个距离就不会再进行调整宽高 this.edgeTopDistance = props.edgeDistance[0] || 10; this.edgeBottomDistance = props.edgeDistance[1] || 10; this.edgeLeftDistance = props.edgeDistance[2] || 10; this.edgeRightDistance = props.edgeDistance[3] || 10; } componentDidMount(){ // body监听移动事件 document.body.addEventListener('mousemove', this.move); // 鼠标松开事件 document.body.addEventListener('mouseup', this.up); } /** * 清除调整宽高的监听 */ clearEventListener() { document.body.removeEventListener('mousemove', this.move); document.body.removeEventListener('mouseup', this.up); } componentWillUnmount() { this.clearEventListener(); } /** * 鼠标松开时结束尺寸修改 */ up = () => { this.reSizeAble = false; this.direction = ""; } /** * 鼠标按下时开启尺寸修改 * @param {*} e * @param {String} direction 记录点击上下左右哪个盒子的标识 */ down = (e, direction) => { this.direction = direction; this.reSizeAble = true; this.clientX = e.clientX; this.clientY = e.clientY; } /** * 鼠标按下事件 监听鼠标移动,修改父节dom位置 * @param {DocumentEvent} e 事件参数 * @param {Boolean} changeLeft 是否需要调整left * @param {Boolean} changeTop 是否需要调整top * @param {Number} delta 调整位置的距离差 */ changeLeftAndTop = (event, changeLeft, changeTop, delta) => { let ww = document.documentElement.clientWidth; let wh = window.innerHeight; if (event.clientY < 0 || event.clientX < 0 || event.clientY > wh || event.clientX > ww) { return false; } if (changeLeft) { this.containerRef.current.style.left = Math.max(this.containerRef.current.offsetLeft + delta, this.edgeLeftDistance) + 'px'; } if (changeTop) { this.containerRef.current.style.top = Math.max(this.containerRef.current.offsetTop + delta, this.edgeTopDistance) + 'px'; } } /** * 鼠标移动事件 * @param {*} e */ move = (e) => { // 当开启尺寸修改时,鼠标移动会修改div尺寸 if (this.reSizeAble) { let finalValue; // 鼠标按下的位置在上部,修改高度 if (this.direction === "top") { // 1.距离上边缘10 不修改 // 2.因为按着顶部修改高度会修改top、height,所以需要判断e.clientY是否在offsetTop和this.clientY之间(此时说明处于往上移动且鼠标位置在盒子上边缘之下),不应该移动和调整盒子宽高 if (e.clientY <= this.edgeTopDistance || (this.containerRef.current.offsetTop < e.clientY && e.clientY < this.clientY)){ this.clientY = e.clientY; return; } finalValue = Math.max(this.props.minHeight, this.containerRef.current.offsetHeight + (this.clientY - e.clientY)); // 移动的距离,如果移动的距离不为0需要调整高度和top let delta = this.containerRef.current.offsetHeight - finalValue; if(delta !== 0){ this.changeLeftAndTop(e, false, true, delta); this.containerRef.current.style.height = finalValue + "px"; } this.clientY = e.clientY; } else if (this.direction === "bottom") {// 鼠标按下的位置在底部,修改高度 // 1.距离下边缘10 不修改 // 2.判断e.clientY是否处于往下移动且鼠标位置在盒子下边缘之上,不应该调整盒子宽高 if (window.innerHeight - e.clientY <= this.edgeBottomDistance || (this.containerRef.current.offsetTop + this.containerRef.current.offsetHeight > e.clientY && e.clientY > this.clientY)) { this.clientY = e.clientY; return; } finalValue = Math.max(this.props.minHeight, this.containerRef.current.offsetHeight + (e.clientY - this.clientY)); this.containerRef.current.style.height = finalValue + "px"; this.clientY = e.clientY; } else if (this.direction === "right") { // 鼠标按下的位置在右边,修改宽度 // 1.距离右边缘10 不修改 // 2.判断e.clientY是否处于往右移动且鼠标位置在盒子右边缘之左,不应该调整盒子宽高 if (document.documentElement.clientWidth - e.clientX <= this.edgeRightDistance || (this.containerRef.current.offsetLeft + this.containerRef.current.offsetWidth > e.clientX && e.clientX > this.clientX)) { this.clientX = e.clientX; return; } // 最小为UI设计this.props.minWidth,最大为 改边距离屏幕边缘-10,其他同此 let value = this.containerRef.current.offsetWidth + (e.clientX - this.clientX); finalValue = step(value, this.props.minWidth, document.body.clientWidth - this.edgeRightDistance - this.containerRef.current.offsetLeft); this.containerRef.current.style.width = finalValue + "px"; this.clientX = e.clientX; } else if (this.direction === "left") {// 鼠标按下的位置在左边,修改宽度 // 1.距离左边缘10 不修改 // 2.因为按着顶部修改高度会修改left、height,所以需要判断e.clientY是否在offsetLeft和this.clientY之间(此时说明处于往左移动且鼠标位置在盒子左边缘之左),不应该移动和调整盒子宽高 if (e.clientX <= this.edgeLeftDistance || (this.containerRef.current.offsetLeft < e.clientX && e.clientX < this.clientX)) { this.clientX = e.clientX; return; } let value = this.containerRef.current.offsetWidth + (this.clientX - e.clientX); finalValue = step(value, this.props.minWidth, this.containerRef.current.offsetWidth - this.edgeLeftDistance + this.containerRef.current.offsetLeft); // 移动的距离,如果移动的距离不为0需要调整宽度和left let delta = this.containerRef.current.offsetWidth - finalValue; if(delta !== 0){ // 需要修改位置,直接修改宽度只会向右增加 this.changeLeftAndTop(e, true, false, delta); this.containerRef.current.style.width = finalValue + "px"; } this.clientX = e.clientX; } this.props.dragCallback && this.props.dragCallback(this.direction, finalValue); } } render() { // 四个红色盒子 用于鼠标移动到上面按下进行拖动 const children = ( <Fragment key={"alphaBar"}> <div key={1} className={styles.alphaTopBar} onMouseDown={(e) => this.down(e, "top")}></div> <div key={2} className={styles.alphaBottomBar} onMouseDown={(e) => this.down(e, "bottom")}></div> <div key={3} className={styles.alphaLeftBar} onMouseDown={(e) => this.down(e, "left")}></div> <div key={4} className={styles.alphaRightBar} onMouseDown={(e) => this.down(e, "right")}></div> </Fragment> ); // 给传进来的children进行加强:添加position:"absolute",添加四个用于拖动的透明盒子 const childrenProps = this.props.children.props; const cloneReactElement = React.cloneElement( this.props.children, { style: { // 复用原来的样式 ...childrenProps.style, // 添加position:"absolute" position: "absolute" }, ref: this.containerRef }, // 复用children,添加四个用于拖动的红色盒子 [childrenProps.children, children] ); return ( <Fragment> { cloneReactElement } </Fragment> ); } } /** * 取最大和最小值之间的值 * @param {*} value * @param {*} min * @param {*} max * @returns */ function step(value, min, max) { if (value < min) { return min; } else if (value > max) { return max; } else { return value; } } export default DragBox;
### DragBox组件拖动条的样式
.alphaTopBar{ position: absolute; width: 100%; height: 8px; top: -5px; left: 0; background-color: red; cursor: row-resize; } .alphaBottomBar{ position: absolute; width: 100%; height: 8px; bottom: -5px; left: 0; background-color: red; cursor: row-resize; } .alphaLeftBar{ position: absolute; width: 8px; height: 100%; top: 0; left: -5px; background-color: red; cursor: col-resize; } .alphaRightBar{ position: absolute; width: 8px; height: 100%; top: 0; right: -5px; background-color: red; cursor: col-resize; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
原文出处:https://blog.csdn.net/weixin_44065125/article/details/122805
相关文章
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误(解决方案)
这篇文章主要介绍了关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误,本文给大家分享解决方案,需要的朋友可以参考下...2021-05-12React引入antd-mobile+postcss搭建移动端
本文给大家分享React引入antd-mobile+postcss搭建移动端的详细流程,文末给大家分享我的一些经验记录使用antd-mobile时发现我之前配置的postcss失效了,防止大家踩坑,特此把解决方案分享到脚本之家平台,需要的朋友参考下吧...2021-06-21- 这篇文章主要介绍了React使用高德地图的实现示例(react-amap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-18
使用 React 和 Threejs 创建一个VR全景项目的过程详解
这篇文章主要介绍了使用 React 和 Threejs 创建一个VR全景项目的过程详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06- 思路其实没有那么复杂,把地图想成一个盒子容器,地图中心点想成盒子中心点;扎点在【地图中心点】不会动,当移动地图时,去获取【地图中心点】经纬度,设置某个位置的时候,将经纬度设置为【地图中心点】即可...2021-06-20
- 这篇文章主要为大家详细介绍了React列表栏及购物车组件使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-06-28
- 这篇文章主要介绍了react使用antd表单赋值,用于修改弹框的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
- 本文主要介绍了element表格行列拖拽的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-02
- 这篇文章主要介绍了React Native 启动流程简析,文以 react-native-cli 创建的示例工程(安卓部分)为例,给大家分析 React Native 的启动流程,需要的朋友可以参考下...2021-08-18
- 这篇文章主要介绍了一百多行代码实现react拖拽hooks,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-21
- 这篇文章主要为大家详细介绍了C#控件Picturebox实现鼠标拖拽功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- useState 通过在函数组件里调用它来给组件添加一些内部 state,React 会在重复渲染时保留这个 state,接下来通过一个示例来看看怎么使用 useState吧...2021-06-04
javascript轻量级库createjs使用Easel实现拖拽效果
这篇文章主要介绍了javascript轻量级库createjs使用Easel实现拖拽效果的相关资料,需要的朋友可以参考下...2016-02-21- 高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意,本文给大家分享React 高阶组件HOC使用小结,一起看看吧...2021-06-13
- 这篇文章主要介绍了React中使用setInterval函数的实例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06
- 这篇文章主要介绍了vue element el-transfer增加拖拽功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-16
- 本文主要介绍了react为什么不推荐使用index作为key,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-07-22
关于antd tree和父子组件之间的传值问题(react 总结)
这篇文章主要介绍了关于antd tree 和父子组件之间的传值问题,是小编给大家总结的一些react知识点,本文通过一个项目需求实例代码详解给大家介绍的非常详细,需要的朋友可以参考下...2021-06-02- element的dialog弹框在项目中挺常用的。拖拽形式的弹框会提高用户体验,本文实现了vue可拖拽的dialog弹框,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-14