为什么我的可拖动 svelte 在缩放后不能正常工作?

Why doesn't my draggable svelte work properly after scaling it?

我创建了一个允许拖动 Dom 元素的 svelte 组件:

<script>
    export let posX = 0
    export let posY = 0

    let moving = false
    let offsetX
    let offsetY

    function dragStart(e) {
        const rect = e.currentTarget.getBoundingClientRect()

        offsetX = e.pageX - rect.left
        offsetY = e.pageY - rect.top

        moving = true
    }

    function dragStop() {
        moving = false
    }

    function dragMove(e) {
        if (moving) {
            posX = e.pageX - offsetX
            posY = e.pageY - offsetY
        }
    }
</script>

<style>
    .draggable {
        user-select: none;
        position: absolute;
        cursor: grab;
    }

    .draggable:active {
        cursor: grabbing;
    }
</style>

<svelte:window on:mouseup={dragStop} on:mousemove={dragMove} />

<div
    on:mousedown={dragStart}
    style="top: {posY}px; left: {posX}px;"
    class="draggable"
>
    <slot/>
</div>

当我将 CSS 属性 transform: scale(0.5); 添加到包含可拖动组件的 div 时,可拖动组件按预期停止工作。他们的位置偏离鼠标位置。

<script>
    import Draggable from "./Draggable.svelte"
</script>

<style>
    .box {
        background: red;
        width: 150px;
        height: 150px;
    }
    
    .container {
        transform: scale(0.5);
    }
</style>

<div class="container">
    <Draggable>
        <div class="box"/>
    </Draggable>
    
    <Draggable posY={250}>
        <div class="box"/>
    </Draggable>
</div>

这是一个 link 到精巧的 REPL:https://svelte.dev/repl/679692b94afc48b48a2a3ebd39875ea0?version=3.42.5

我该如何解决这个问题?

提前致谢!

缩小容器时,会发生两件事:

  1. 容器大小变得小于视口,导致鼠标位置偏移未更正。
  2. top/left CSS 属性的单位现在是原来的一半大,也没有更正。

要解决此问题,我们必须计算父容器相对于视口的偏移量,并将该值传递到您的 <Draggable> 组件中。我们还需要传入我们正在使用的比例值。

<!-- App.svelte -->
<script>
  import {onMount} from "svelte"
    import Draggable from "./Draggable.svelte"
    
    let parent;
    let parentOffset = {x: 0, y:0}
    
    onMount(() => {
        let rect = parent.getBoundingClientRect()
        parentOffset = {x: rect.x, y: rect.y}
    })
</script>

<style>
    .box {
        background: red;
        width: 150px;
        height: 150px;
    }
    
    .container {
        transform: scale(0.5);
    }
</style>

<div class="container" bind:this={parent}>
    <Draggable {parentOffset} scale={0.5}>
        <div class="box"/>
    </Draggable>
    
    <Draggable posY={250} {parentOffset} scale={0.5}>
        <div class="box"/>
    </Draggable>
</div>
<!-- Draggable.svelte -->
<script>
    export let posX = 0
    export let posY = 0
        
        export let parentOffset;
      export let scale;

    let moving = false
    let offsetX
    let offsetY

    function dragStart(e) {
        const rect = e.currentTarget.getBoundingClientRect()

        offsetX = e.pageX - rect.left
        offsetY = e.pageY - rect.top

        moving = true
    }

    function dragStop() {
        moving = false
    }

    function dragMove(e) {
        if (moving) {
            // new math! we subtract the parent offset to correct the parent shift
            // and also divide by the scale to correct the scale multiplication
            posX = ((e.pageX - offsetX)-parentOffset.x)/scale
            posY = ((e.pageY - offsetY)-parentOffset.y)/scale
        }
    }
</script>

<style>
    .draggable {
        user-select: none;
        position: absolute;
        cursor: grab;
    }

    .draggable:active {
        cursor: grabbing;
    }
</style>

<svelte:window on:mouseup={dragStop} on:mousemove={dragMove} />

<div
    on:mousedown={dragStart}
    style="top: {posY}px; left: {posX}px;"
    class="draggable"
>
    <slot/>
</div>

新 REPL:https://svelte.dev/repl/9ec1a1598e8f407e8ec807dbb8a4d92b?version=3.42.5