React拖拽调整大小的组件

React拖拽调整大小的组件

本文实例为大家分享了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;   }

推荐阅读

    React解决长列表方案|react-virtualized

    React解决长列表方案|react-virtualized,元素,过程,github地址高效渲染大型列表的响应式组件 使用窗口特性,即在一个滚动的范围内,呈现你

    ReactOS是什么

    ReactOS是什么,审查,开发者,通用,开放源码,项目,维护,  ReactOS是一个开发与Windows NT和Windows 2000 应用程序、硬件驱动程序兼容的开源操

    用React完成一个图片轮播组件

    用React完成一个图片轮播组件,用,React,完成,一个,图片,轮播,组件,使用,React,,  使用React实现上述功能,首先,划分组件:  <SlideMS><Sli

    初学react用什么书籍

    初学react用什么书籍,初学,react,用,什么,书籍,初学,react,用,什么,,  初学react用什么书籍?  如果你没接触过JS,那么就要从JS基础开始

    Vue3.0API介绍中reactive使用示例

    Vue3.0API介绍中reactive使用示例,Vue3.0API,介绍,中,reactive,使用,示例,Vue3.0API,,Vue3.0API介绍中reactive使用示例reactive返回对象

    Angular 4.x中表单Reactive Forms详解

    这篇文章主要介绍了Angular 4.x中表单Reactive Forms的相关资料,文中通过示例代码介绍的非常详细,相信对大家具有一定的参考价值,需要的朋