Search code examples
javascriptvue.jsvuejs2draggable

Dragging an element inside a div but the element flashes when dragged


I'm trying to drag an element around inside another div but it is constantly flashing when being dragged around. I recreated the problem with this sandbox https://codesandbox.io/s/focused-cache-l3yos

<template>
  <div id="app">
    <div id="board" @mousemove="dragOver">
      <div
        class="draggableItem"
        @mousedown="dragStart"
        @mouseup="dragStop"
        :style="{top: this.top + 'px', left: this.left + 'px'}"
      >This should be draggable</div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data: function() {
    return {
      isDragging: false,
      top: 50,
      left: 50
    };
  },
  methods: {
    dragOver: function(e) {
      if (this.isDragging) {
        this.left = e.offsetX;
        this.top = e.offsetY;
      }
    },
    dragStart: function(e) {
      this.isDragging = true;
    },
    dragStop: function(e) {
      this.isDragging = false;
    }
  }
};
</script>

Solution

  • You can calculate the position as an offset from start position, and then update it based on the movement. This will allow to draw by any part. You can (and should IMHO) attach and remove the event handlers dynamically.

    Here is what that might look like:

    <template>
      <div id="app">
        <div id="board">
          <div
            class="draggableItem"
            @mousedown="dragStart"
            :style="{top: this.top + 'px', left: this.left + 'px'}"
          >This should be draggable</div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: "App",
      data: function() {
        return {
          isDragging: false,
          top: 50,
          left: 50,
          startTop: 0,
          startLeft: 0
        };
      },
      methods: {
        dragOver: function(e) {
          if (this.isDragging) {
            this.top = e.clientY - this.startTop;
            this.left = e.clientX - this.startLeft;
          }
        },
        dragStart: function(e) {
          window.addEventListener('mousemove', this.dragOver)
          window.addEventListener('mouseup', this.dragStop)
          this.isDragging = true;
          this.startTop = e.clientY - this.top;
          this.startLeft = e.clientX - this.left;
        },
        dragStop: function(e) {
          window.removeEventListener('mousemove', this.dragOver)
          window.removeEventListener('mouseup', this.dragStop)
          this.isDragging = false;
        }
      }
    };
    </script>