前言:
最近写一个项目遇到了需要拉伸调整一个元素得大小(宽高)。所以打算实现一下。
思路就是用 mousedown、mousemove、mouseup 来实现。
mousemove是动态获取坐标,然后 动态改变元素宽度
js自己实现:
html里实现:
<!DOCTYPE html>
<html>
<head>
<style>
.container {
width: 400px;
height: 300px;
border: 1px solid #000;
position: relative;
}
.box {
width: 300px;
height: 200px;
border: 1px solid #000;
resize: horizontal;
overflow: auto;
position: relative;
}
.button {
width: 8px;
height: 8px;
background-color: #f00;
cursor: pointer;
position: absolute;
}
.right-button {
right: -4px;
top: 50%;
transform: translateY(-50%);
}
.bottom-button {
bottom: -4px;
left: 50%;
transform: translateX(-50%);
}
</style>
</head>
<body>
<div class="container">
<div class="box">
Content
<div class="button right-button"></div>
</div>
<div class="button bottom-button"></div>
</div>
<script>
const box = document.querySelector('.box');
const rightButton = document.querySelector('.right-button');
const bottomButton = document.querySelector('.bottom-button');
let startX = 0;
let startY = 0;
let initialWidth = 0;
let initialHeight = 0;
function startResize(event) {
event.preventDefault();
startX = event.clientX;
startY = event.clientY;
initialWidth = parseInt(document.defaultView.getComputedStyle(box).width, 10);
initialHeight = parseInt(document.defaultView.getComputedStyle(box).height, 10);
document.documentElement.addEventListener('mousemove', resize);
document.documentElement.addEventListener('mouseup', stopResize);
}
function resize(event) {
const deltaX = event.clientX - startX;
const deltaY = event.clientY - startY;
const newWidth = initialWidth + deltaX;
const newHeight = initialHeight + deltaY;
box.style.width = `${newWidth}px`;
box.style.height = `${newHeight}px`;
}
function stopResize() {
document.documentElement.removeEventListener('mousemove', resize);
document.documentElement.removeEventListener('mouseup', stopResize);
}
rightButton.addEventListener('mousedown', startResize);
bottomButton.addEventListener('mousedown', startResize);
</script>
</body>
</html>
react里封装一个组件
hook 语法组件:
import React, { ReactNode, useState, useEffect } from 'react';
import styles from "./index.less";
interface ResizableBoxProps {
/**
* 盒子的宽度 默认100
*/
widthNum?: number;
/**
* 盒子的高度 默认50
*/
heightNum?: number;
/**
* 内容
*/
content?: string | ReactNode;
}
const ResizableBox: React.FC<ResizableBoxProps> = ({
widthNum,
heightNum,
content,
children,
...props
}) => {
// 根据优先级选择要渲染的标题
const contentRender = content || children;
// 定义状态变量,使用useState
const [width, setWidth] = useState(widthNum || 100); // 宽度
const [height, setHeight] = useState(heightNum || 50); // 高度
const [startX, setStartX] = useState(0); // 鼠标点击时的起始X坐标
const [startY, setStartY] = useState(0); // 鼠标点击时的起始Y坐标
const [initialWidth, setInitialWidth] = useState(0); // 调整大小前的初始宽度
const [initialHeight, setInitialHeight] = useState(0); // 调整大小前的初始高度
const [isResizing, setIsResizing] = useState(false); // 是否正在调整大小
/**开始调整大小时的事件处理函数 高度*/
const startResizeY = (event: any) => {
event.preventDefault();
const { clientX, clientY } = event;
setStartY(clientY);
setInitialHeight(height);
setIsResizing(true);
document.documentElement.addEventListener('mousemove', resizeY);
document.documentElement.addEventListener('mouseup', stopResize);
};
/**开始调整大小时的事件处理函数 宽度*/
const startResizeX = (event: any) => {
event.preventDefault();
const { clientX, clientY } = event;
setStartX(clientX);
setInitialWidth(width);
setIsResizing(true);
document.documentElement.addEventListener('mousemove', resizeX);
document.documentElement.addEventListener('mouseup', stopResize);
};
/** 宽度调整大小 */
const resizeX = (event: any) => {
const { clientX } = event;
const deltaX = clientX - startX;
const newWidth = initialWidth + deltaX;
setWidth(newWidth);
};
/**高度调整大小 */
const resizeY = (event: any) => {
const { clientY } = event;
const deltaY = clientY - startY;
const newHeight = initialHeight + deltaY;
setHeight(newHeight);
};
// 停止调整大小时的事件处理函数
const stopResize = () => {
setIsResizing(false);
document.documentElement.removeEventListener('mousemove', resizeX);
document.documentElement.removeEventListener('mousemove', resizeY);
document.documentElement.removeEventListener('mouseup', stopResize);
};
// useEffect用于设置鼠标样式
useEffect(() => {
if (isResizing) {
// document.documentElement.style.cursor = 'nwse-resize';
} else {
document.documentElement.style.cursor = 'default';
}
}, [isResizing]);
// 返回可调整大小的组件
return (
<div
className={styles.resizable_box}
style={{ width: `${width}px`, height: `${height}px` }} // 使用状态变量控制宽度和高度
>
<div className={styles.container}>
{contentRender}
</div>
<div className={`${styles.button} ${styles.right_button}`} onMouseDown={startResizeX}></div>
<div className={`${styles.button} ${styles.bottom_button}`} onMouseDown={startResizeY}></div>
</div>
);
};
export default ResizableBox;
样式less:
.resizable_box {
position: relative;
}
.container {
width: 100%;
height: 100%;
}
// .button {
// width: 8px;
// height: 8px;
// background-color: #f00;
// /* cursor: pointer; */
// position: absolute;
// }
.button {
// width: 2px;
// height: 100%;
background: none;
position: absolute;
}
.right_button {
width: 2px;
height: 100%;
right: -2px;
top: 0;
// top: 50%;
// transform: translateY(-50%);
cursor: e-resize;
}
.bottom_button {
width: 100%;
height: 2px;
bottom: -2px;
// left: 50%;
// transform: translateX(-50%);
cursor: n-resize;
}
使用 方式:
//换成自己的
import ResizableBox from "xxx/components/ResizableBox";
<ResizableBox widthNum={220} heightNum={300}>
<div style={{width:"100%",background:"red",height:"100%"}}>
ttt
</div>
</ResizableBox>
使用插件:
js:
Interact.js
一个现代、强大的拖放、调整大小和手势识别的JavaScript库。
提供了许多可定制的选项和事件回调。
https://interactjs.io/ 官网
jQuery UI
jQuery的UI组件库,包括可拖拽(Draggable)和可调整大小(Resizable)的组件。
提供了丰富的配置选项和事件处理。
示例:使用jQuery UI的Resizable
react:
react-resizable
特点:专为React设计的,允许你轻松地为React组件添加拖拽调整大小的功能。
安装:通过npm或yarn安装,如npm install react-resizable。
使用:
引入Resizable组件。
在你的React组件中包裹需要拉伸的元素。
通过props配置拉伸的初始大小、最小和最大尺寸等。
re-resizable(注意:这可能与react-resizable不同,但同样适用于React)
特点:类似于react-resizable,但可能提供了一些额外的功能或定制选项。
安装:通过npm或yarn安装,如npm install --save re-resizable。
使用:
引入Resizable组件。
在你的React组件中使用Resizable来包裹需要拉伸的元素。
可以通过props配置拉伸的默认大小、最小和最大尺寸、拉伸手柄的样式等。
react-rnd
特点:除了提供拉伸功能外,还允许你通过拖拽来移动元素。
安装:通过npm或yarn安装,如npm install react-rnd。
使用:
引入Rnd组件。
在你的React组件中使用Rnd来包裹需要拉伸和移动的元素。
可以通过props配置元素的初始位置、大小、移动和拉伸的限制等。
示例:参考文章3提供了一个使用react-rnd实现元素拖动和缩放的实例。
vue:
Vue-Resizable
这个库提供了一个可调整大小的组件,可以用于实现元素的拉伸和调整大小功能。
Vue-Draggable-Resizable
这个库结合了拖动和调整大小的功能,可以让你通过拖动和拉伸来改变元素的尺寸。
Vue-Resize-Handle
这个库提供了一个可自定义样式的调整大小的手柄,可以用于在元素上添加拉伸功能。
Vue-Drag-Resize
这个库提供了拖动和调整大小的能力,可以用于在元素上实现拉伸和调整大小的效果。
总结:
这种功能建议使用 成熟的库来实现,兼容性什么的一般都会适配。