2

我创建了一个纤细的组件来允许可拖动的 Dom 元素:

<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>

这是一个纤细的 REPL 的链接:https ://svelte.dev/repl/679692b94afc48b48a2a3ebd39875ea0?version=3.42.5

我将如何解决这个问题?

提前致谢!

4

1 回答 1

1

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

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

为了解决这个问题,我们必须计算父容器相对于视口的偏移量,并将该值传递给您的<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

于 2021-09-16T02:24:12.950 回答