loading...
Cover image for Vue JS: Draggable div

Vue JS: Draggable div

mandrewcito profile image Andrés Baamonde Lozano Updated on ・2 min read

vue examples (6 Part Series)

1) Vue JS: Draggable div 2) Vue JS: Generic list 3 ... 4 3) Vue JS: Notifications with mini-toastr and vue events 4) VueJS: Rating component with stars 5) VueJS: Scroll top component 6) VueJS: Double range slider component

Theese days I have been working on my personal website, i have decided to build an tiny terminal for quering my info. My personal info is also avaiable on the website but a developer's personal website needs to be a bit nerd :D. Website is build with vuejs and bootstrap.

I'm a guy that doesn't like design so my website will not be prettiest in the world but at least, i´m trying to make it functional. Site will be an index of my projects (python libraries especially), usefull links that i been storing during this working years. And of course a CV, but it will be last part.

Component implementation

First, you need implement the component, i choose a component that delegates movement of container on header, you can move function 'drag MouseDown' to modify the behaviour.

Template

Really simple, template with 3 slots for easy custom our component

Script

We will need 3 methods:

  • onclick to start dragging. This method will register two functions to handle movement: onmousemove and mouseup. Also, it will register the first position of the container.
  • onmousemove: Will update position of our container.
  • mouseup: Will delete function handlers for functions onmousemove and itself.

CSS

Only need position absolute and a z-index higher than the other page components

Draggable div component

<template>
  <div ref="draggableContainer" id="draggable-container">
    <div id="draggable-header" @mousedown="dragMouseDown">
      <slot name="header"></slot>
    </div>
    <slot name="main"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script>
export default {
  name: 'DraggableDiv',
  data: function () {
    return {
      positions: {
        clientX: undefined,
        clientY: undefined,
        movementX: 0,
        movementY: 0
      }
    }
  },
  methods: {
    dragMouseDown: function (event) {
      event.preventDefault()
      // get the mouse cursor position at startup:
      this.positions.clientX = event.clientX
      this.positions.clientY = event.clientY
      document.onmousemove = this.elementDrag
      document.onmouseup = this.closeDragElement
    },
    elementDrag: function (event) {
      event.preventDefault()
      this.positions.movementX = this.positions.clientX - event.clientX
      this.positions.movementY = this.positions.clientY - event.clientY
      this.positions.clientX = event.clientX
      this.positions.clientY = event.clientY
      // set the element's new position:
      this.$refs.draggableContainer.style.top = (this.$refs.draggableContainer.offsetTop - this.positions.movementY) + 'px'
      this.$refs.draggableContainer.style.left = (this.$refs.draggableContainer.offsetLeft - this.positions.movementX) + 'px'
    },
    closeDragElement () {
      document.onmouseup = null
      document.onmousemove = null
    }
  }
}
</script>

<style>
#draggable-container {
  position: absolute;
  z-index: 9;
}
#draggable-header {
  z-index: 10;
}
</style>

Component use example

Components with slots are really easy to use on vue you only need to create a tag template with attribute slot, slot value will be target component

Temmplate

<template>
  <DraggableDiv class="col-11">
    <template slot="header">
      [[[ SOME CONTENT HERE]]]
    </template>
    <template slot="main" >
      [[[ SOME CONTENT HERE]]]
    </template>
    <template slot="footer">
      [[[ SOME CONTENT HERE]]]
    </template>
  </DraggableDiv>
</template>

Script

<script>
import DraggableDiv from './DraggableDiv'
export default {
  components: {
    DraggableDiv
  }
}
</script>

Thats all

I used this component to implement a draggable terminal for my personal website, the result looks like this.
Demo drag and drop

If any of you wants a post of my terminal implementation on javascript leave a comment below :D

References

vue examples (6 Part Series)

1) Vue JS: Draggable div 2) Vue JS: Generic list 3 ... 4 3) Vue JS: Notifications with mini-toastr and vue events 4) VueJS: Rating component with stars 5) VueJS: Scroll top component 6) VueJS: Double range slider component

Discussion

markdown guide