图片拖拽+自定义大小

本文直接贴全部代码,详情内容和gif动图效果可直接点击转载的网站观看:react 实现div缩放、旋转、拖拽的9个控制点 - JavaShuo

import React, {Component, useState, useRef, useCallback} from 'react';

/**
 * 元素变化。 方法放在组件外部或者其余地方。
 * @param direction  方向 // move 移动 / 'e', 'w', 's', 'n', 'ne', 'nw', 'se', 'sw'
 * @param oriStyle 元素的属性 width height top left
 * @param oriPos   鼠标按下时所记录的坐标
 * @param e        事件event
 */

function transform(direction, oriPos, e) {
	const style = {...oriPos.current};
	const offsetX = e.clientX - oriPos.current.cX;
	const offsetY = e.clientY - oriPos.current.cY;
	switch (direction.current) {
		// 东
		case 'e':
			// 向右拖拽添加宽度
			style.width += offsetX;
			return style;
		// 西
		case 'w':
			// 增长宽度、位置同步左移
			style.width -= offsetX;
			style.left += offsetX;
			return style;
		// 南
		case 's':
			style.height += offsetY;
			return style;
		// 北
		case 'n':
			style.height -= offsetY;
			style.top += offsetY;
			break;
		// 东北
		case 'ne':
			style.height -= offsetY;
			style.top += offsetY;
			style.width += offsetX;
			break;
		// 西北
		case 'nw':
			style.height -= offsetY;
			style.top += offsetY;
			style.width -= offsetX;
			style.left += offsetX;
			break;
		// 东南
		case 'se':
			style.height += offsetY;
			style.width += offsetX;
			break;
		// 西南
		case 'sw':
			style.height += offsetY;
			style.width -= offsetX;
			style.left += offsetX;
			break;
		default:
			// 元素当前位置 + 偏移量
			// eslint-disable-next-line no-case-declarations
			const top = oriPos.current.top + offsetY;
			// eslint-disable-next-line no-case-declarations
			const left = oriPos.current.left + offsetX;
			// 限制必须在这个范围内移动 画板的高度-元素的高度
			style.top = Math.max(0, Math.min(top, 500 - style.height));
			style.left = Math.max(0, Math.min(left, 500 - style.width));
			break;
	}
	return style;
}

// 东南西北, 东北、西北、东南、西南
// const points = ['e', 'w', 's', 'n', 'ne', 'nw', 'se', 'sw']
const points = ['ne', 'nw', 'se', 'sw'];

function Drawing() {
	// 画板的
	const wrapStyle = {
		left: 100,
		top: 100,
		width: 500,
		height: 500
	};
	const [style, setStyle] = useState({
		left: 100,
		top: 100,
		width: 100,
		height: 100
	});
	// 初始数据, 由于不须要从新render 因此用 useRef
	const oriPos = useRef({
		top: 0, // 元素的坐标
		left: 0,
		cX: 0, // 鼠标的坐标
		cY: 0
	});
	const isDown = useRef(false);

	// 鼠标被按下
	const onMouseDown = useCallback((dir, e) => {
		// 阻止事件冒泡
		e.stopPropagation();
		// 保存方向。
		points.current = dir;
		isDown.current = true;
		// 而后鼠标坐标是
		const cY = e.clientY; // clientX 相对于可视化区域
		const cX = e.clientX;
		oriPos.current = {
			...style,
			cX,
			cY
		};
	});

	// 鼠标移动
	const onMouseMove = useCallback(e => {
		// 判断鼠标是否按住
		if (!isDown.current) return;
		const newStyle = transform(points, oriPos, e);
		setStyle(newStyle);
	});

	// 鼠标被抬起
	const onMouseUp = useCallback(e => {
		// 阻止事件冒泡
		e.stopPropagation();
		isDown.current = false;
	});

	return (
		<div style={wrapStyle} className="drawing-wrap" onMouseDown={e => onMouseDown(_, e)} onMouseUp={onMouseUp} onMouseMove={onMouseMove}>
			<div className="drawing-item" style={style}>
				{points.map(item => (
					<div onMouseDown={e => onMouseDown(item, e)} onMouseMove={onMouseMove} key={item} className={`control-point point-${item}`}></div>
				))}
			</div>
		</div>
	);
}
export default Drawing;
.drawing-wrap{
        width: 500px;
        height: 500px;
        border: 1px solid red ;
        position: relative;
    }
    .drawing-item {
        cursor: move;
        width: 100px;
        height: 100px;
        background-color: #ccc;
        position: absolute;
        top: 100px;
        left: 100px;
        box-sizing: border-box;
    
    }
    .control-point{
        position: absolute;
        box-sizing: border-box;
        display: inline-block;
        background: #fff;
        border: 1px solid #c0c5cf;
        box-shadow: 0 0 2px 0 rgba(86, 90, 98, .2);
        border-radius: 6px;
        padding: 5px;
        margin-top: -5px !important;
        margin-left: -5px !important;
        user-select: none;   // 注意禁止鼠标选中控制点元素,否则拖拽事件可能会所以被中断
    }
    .control-point.point-e{
        cursor: ew-resize;
        left: 100%;
        top: 50%;
        margin-left: 1px;
        opacity: 0;
    }
    .control-point.point-n{
        cursor: ns-resize;
        left: 50%;
        margin-top: -1px;
        opacity: 0;
    }
    .control-point.point-s{
        cursor: ns-resize;
        left: 50%;
        top: 100%;
        margin-top: 1px;
        opacity: 0;
    }
    .control-point.point-w{
        cursor: ew-resize;
        top: 50%;
        left: 0;
        margin-left: -1px;
        opacity: 0;
    }
    .control-point.point-ne {
        cursor: nesw-resize;
        left: 100%;
        margin-top: -1px;
        margin-left: 1px;
        opacity: 0;
    }
    .control-point.point-nw {
        cursor: nwse-resize;
        top: 0;
        left: 0;
        margin-left: -1px;
        margin-top: -1px;
        opacity: 0;
    }
    .control-point.point-se {
        cursor: nwse-resize;
        left: 100%;
        top: 100%;
        margin-left: 1px;
        margin-top: 1px;
        opacity: 0;
    }
    .control-point.point-sw {
        cursor: nesw-resize;
        top: 100%;
        left: 0;
        margin-left: -1px;
        margin-top: 1px;
        opacity: 0;
    }

转载地址:react 实现div缩放、旋转、拖拽的9个控制点 - JavaShuo这段时间一个canvas 库所实现的元素拖拽控制,以为很不错。因而本身用js + div 来实现一个。用了react 框架,练练手。 思路 在被控制的元素的四条边和四个角添加8个控制点控制点。拖拽控制点时判断拖拽的方向,计算偏移量。修改元素的top、left、width、height。 旋转功能是经过三角函数计算鼠标拖动后的角度。动态修改元素的rotatecss 画板(舞台) 想要对元素进行控制。http://www.javashuo.com/article/p-fjldvqtm-ny.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值