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中usememo与usecallback的区别
  • react项目从新建到部署的实现示例
  • react-player实现视频播放与自定义进度条效果
  • d3.js(v3)+react 实现带坐标与比例尺的柱形图 (v3版本)
  • react为什么不推荐使用index作为key
  • 深入浅析react native es6语法
  • react native 中添加自定义字体的方法
  • react mpa 多页配置详解
  • 深入理解react native核心原理(react native的桥接(bridge)
  • 详解react native fetch遇到的坑
  • React中路由有哪些常用组件?说明它们的作用
  • react中如何快速创建含有connect的组件?
  • react如何根据字符串生成组件
  • Vue和React组件之间的传值方式详解?
  • -native动态切换tab组件的方法
  • 尝试自己动手用react来写一个分页组件(小结)
  • React有哪些UI组件库
  • React为 Vue 引入容器组件和展示组件的教程详解
  • 如何使用React Native Android 实现本地组件的安装
  • 如何使用React Native Android 实现本地组件的安装
  • 使用React实现轮播效果组件示例代码
  • 如何使用React构建一个简单布局组件
  • react中怎样在父组件中获取子组件中的Dom
  • -native 怎么调用原生组件
  • react 不用redux能做到组件复用么
  • -router V4 的route组件还支持path属性的通配符么
  • react父亲怎么获取子组件的state
  • react怎么一次渲染多个组件
  • 用 react native 的朋友,当react native 引入一些组件后,项目运行...
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全yui.ext相关prototypejqueryangularjsjsonlib_jsjs面向对象extjsmootoolsseajsdojovue.jsbackbone.jsreact其它首页javascriptjavascript类库react 实现拖拽功能的示例代码再次谈论react.js实现原生js拖拽效果引起的一系列问题react.js组件实现拖拽复制和可排序的示例代码使用react-beautiful-dnd实现列表间拖拽踩坑react.js组件实现拖拽排序组件功能过程解析详解gantt甘特图可拖拽、编辑(vue、react都可用?highcharts)react实现简单的拖拽功能基于react.js实现原生js拖拽效果引发的思考react-beautiful-dnd 实现组件拖拽功能一百多行代码实现react拖拽hooks解析react中usememo与usecallback的区别react项目从新建到部署的实现示例react-player实现视频播放与自定义进度条效果d3.js(v3)+react 实现带坐标与比例尺的柱形图 (v3版本)深入浅析react native es6语法react native 中添加自定义字体的方法react mpa 多页配置详解深入理解react native核心原理(react native的桥接(bridge)详解react native fetch遇到的坑详解react中传入组件的props改变时更新组件的几种实现vscode配置react开发环境的步骤react-redux中connect的装饰器用法@connreactnative 之flatlist使用及踩坑封装总结详解react native开源时间日期选择器组件(reacreact native实现简单的登录功能(推荐)react-router browserhistory刷新页reactnative之键盘keyboard的弹出与消失示例详解react-router中url参数改变页面不刷新的解决详解各版本react路由的跳转的方法react中ref 的使用方法详解如何深入理解react的ref 属性react最流行的生态替代antdpro搭建轻量级后台管理react使用axios实现上传下载功能react-player实现视频播放与自定义进度条效果react native listview 增加顶部下拉刷新和底下点击刷新示使用 react 和 threejs 创建一个vr全景项目的过程详解react diff原理深入分析详解基于webpack搭建react运行环境react获取input值并提交的2种方法实例
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved