React 中的可移动/可拖动 <div>

Move-able / Drag-able <div> in React

我目前正在尝试制作一个可编辑区域以显示在购物网站内的图片上。

目标是使用 React 制作一张带有可以移动和调整大小的方框的图片。

我一直在关注来自 youtube 的 javascript 教程,但是它并没有像我预期的那样运行。

下面是我使用的代码:

import React, { useState } from "react";
import axios from "axios";
import Delete from "../Buttons/Delete";
import Picture from "../Picture/Picture";

function EditableImageUploader(props){
    const [  loading, setLoading ] = useState(false);
    const editableArea = document.querySelector(".editableArea");
    const pictureEdit = document.querySelector(".pictureEdit");

    const uploadImage = async e => {
        const files = e.target.files
        const data = new FormData()
        data.append('file', files[0])
        data.append('upload_preset', 'charlotte-co')
        setLoading(true)
        axios.post('https://api.cloudinary.com/v1_1/charlotte-co/image/upload', data)
            .then(res => {
                setLoading(false);
                props.setImages([...props.images, res.data]);
            })
            .catch(err =>console.log(err));
    }

    function moveDiv(e){
        window.addEventListener("mousemove", mouseMove);
        window.addEventListener("mouseup", mouseRelease);
        let prevX = e.clientX;
        let prevY = e.clientY;

        function mouseMove(e){     
            let newX = prevX - e.clientX;
            let newY = prevY - e.clientY;
            console.log(prevY)
            console.log(`Y = ${e.clientY}`)
            console.log(prevX)
            console.log(`X = ${e.clientX}`)

            const rect = editableArea.getBoundingClientRect()
            editableArea.style.left = (rect.left - newX) + "px";
            editableArea.style.top = (rect.top - newY) + "px";
        }

        function mouseRelease(){
            window.removeEventListener("mousemove", mouseMove);
            window.removeEventListener("mouseup", mouseRelease);

            prevX = e.clientX;
            prevY = e.clientY; 
        }
    }

    return(<>
        <div className="image-uploader">
            {(props.images)?"":(<input
                type="file"
                name="file"
                placeholder="Upload a File"
                className="uploader"
                onChange={uploadImage}
            />)}
            <div>
                {loading ? (
                    <h4>loading...</h4>
                ):""}
                {(props.images)?(
                    props.images.map(image => {
                        return (<>
                            <Delete 
                                delete={image.public_id}
                                deleteFrom={props.images}
                                setDeleteFrom={props.setImages}
                            />
                         {

                         }   <Picture
                                className="pictureEdit"
                                publicId={image.public_id}
                                version={image.version}
                                width="300"
                                quality="100"
                            />
                            <div 
                                className="editableArea"
                                onMouseDown={(e)=> moveDiv(e)}
                            >
                                <div className="resizer north"></div>
                                <div className="resizer west"></div>
                                <div className="resizer south"></div>
                                <div className="resizer east"></div>
                                The transfer will spread across this box.
                            </div>
                        </>)
                    })
                ):(<p>No blank image available currently. Upload one to make this option available.</p>)}
            </div>
        </div>
    </>)
}

export default EditableImageUploader;

这里是相关的 CSS:


.editableArea{
    position: absolute;
    background-color: green;
    height: 150px;
    width: 150px;
    border-style: solid;
    border-color: black;
    border-width: 5px;
    z-index: 5;
    cursor: move;
}

它允许您移动 div 并改变它的位置,但它会将它移动到远离它最初定位的位置。

我似乎认为这也是由于页面滚动的位置造成的,但我非常不确定它为什么会这样反应。

当控制台显示:

653
Y = 653
325
X = 367

可编辑区的实际位置在:

left: 1005.55px; 
top: -12346.8px;

如果您能提供任何帮助和/或解释它如何以及为何以这种方式运行以及如何解决此问题,我们将不胜感激。

考虑在您的计算中包括 offsetTop 和 offsetLeft。例如,如果您的 div 没有占用页面宽度和高度的 100%,您得到不同的结果是正常的,因为 clientX 和 clientY 实际上 return 鼠标在屏幕,并且它们与 DOM 元素无关。本文将帮助: How to get an element's top position relative to the browser's viewport?

您还应该考虑的另一件事是开始拖动时单击元素的确切位置。我可以用一个例子来解释:假设您在开始拖动时单击了中间的元素(水平和垂直)。完成计算后,您将获得的位置将设置为顶部和左侧。如果没有这个偏移量,元素不会放在鼠标松开的位置,但会移动一点点(或很多,取决于元素的大小)。

我想帮你写一些代码,但是这会很困难,因为你有很多逻辑,包括资源(图像)和 axios 调用。如果你削减这种逻辑并硬编码一些图像并在在线编辑器和编译器中添加代码并设置一个link,我也会尽力帮助你处理代码。

如果您有任何其他问题,我很乐意提供帮助。