v3

by dapo

HTML

<script src="https://gistcdn.githack.com/dasDaniel/f3cebc1274339055729c6e887ca8d2ad/raw/6862a35fe666dc53fe72f20e3277d1de408e0c5a/vue.global.js"></script>
<div id="app"></div>

<template id="appTemplate">
  <my-component>
    <my-component></my-component>

  </my-component>
</template>

<template id="myComponent">
  <div ref="el" class="dragable" :style="style">
    <h3>DRAG ME</h3>
    <pre>{{ position }}</pre>
    <pre>{{ style }}</pre>
    <slot></slot>
  </div>
</template>

CSS

.dragable {
  font-family: "Lucida Sans", Geneva, Verdana, sans-serif;
  width: 40%;
  max-width: 90%;
  min-width: 320px;
  min-height: 6.5em;
  margin: 0;
  color: rgb(6, 19, 29);
  background-color: rgb(187, 195, 209);
  border-radius: 16px;
  padding: 16px;
  touch-action: none;
  user-select: none;
  -webkit-transform: translate(0px, 0px);
  transform: translate(0px, 0px);
  transition: transform 0.1s ease-in, box-shadow 0.1s ease-out;
  border: 1px solid rgb(6, 19, 29);
}

pre {
  width: 48%;
  display: inline-block;
  overflow: hidden;
  font-size: 10px;
}

JavaScript

const {
    reactive,
    computed,
    ref,
    onMounted,
    watch
  } = Vue;

  const makeDragable = element => {
    const position = reactive({
      init: false,
      x: 0,
      y: 0,
      width: 0,
      height: 0,
      isDraging: false,
      dragStartX: null,
      dragStartY: null
    });

    const style = computed(() => {
      if (position.init) {
        return {
          position: "absolute",
          left: position.x + "px",
          top: position.y + "px",
          width: position.width + "px",
          height: position.height + "px",
          "box-shadow": position.isDraging ? "3px 6px 16px rgba(0, 0, 0, 0.15)" : "",
          "transform": position.isDraging ? "translate(-3px, -6px)" : "",
          "cursor": position.isDraging ? "grab" : "pointer",
        };
      }
      return {};
    });

    const onMouseDown = e => {
      e.stopPropagation();
      let {
        clientX,
        clientY
      } = e;
      position.dragStartX = clientX - position.x;
      position.dragStartY = clientY - position.y;

      position.isDraging = true;

      document.addEventListener("mouseup", onMouseUp);
      document.addEventListener("mousemove", onMouseMove);
    };

    const onMouseMove = e => {
      e.stopPropagation();
      let {
        clientX,
        clientY
      } = e;
      position.x = clientX - position.dragStartX;
      position.y = clientY - position.dragStartY;
    };

    const onMouseUp = e => {
      e.stopPropagation();
      let {
        clientX,
        clientY
      } = e;
      position.isDraging = false;
      position.dragStartX = null;
      position.dragStartY = null;
      document.removeEventListener("mouseup", onMouseUp);
      document.removeEventListener("mousemove", onMouseMove);
    };


    watch(element, element => {
      if (!element instanceof HTMLElement) return;
      let rect = element.getBoundingClientRect(element);
      position.init = true;
      position.x = Math.round(rect.x);
     ...