網站首頁 編程語言 正文
本文實例為大家分享了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/122805664
相關推薦
- 2022-09-10 pycharm中沒有找到database的解決方案_python
- 2022-03-23 C++繼承詳細介紹_C 語言
- 2022-10-30 淺析pytest?鉤子函數?之初始鉤子和引導鉤子_python
- 2022-09-05 C語言中的字符串數據在C中的存儲方式_C 語言
- 2023-02-17 Go語言如何實現TCP通信詳解_Golang
- 2022-11-22 python3.6.4安裝opencv3.4.2的實現_python
- 2022-02-28 npm install安裝報錯 gyp info it worked if it ends with
- 2022-07-06 Python?dataframe如何設置index_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支