Vue JS: Draggable div
Tags: javascript, vue, draganddrop, slots
Published: 2020-03-14 16:53:55

---
title: Vue JS: Draggable div
published: true
description: Drag and drop div with vue from my personal website terminal
tags: javascript, vue, draganddrop, slots
cover_image: https://i.blogs.es/99f0c0/vue/450_1000.png
series: vue examples
---

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](https://vuejs.org/) and [bootstrap](https://getbootstrap.com/).

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

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

```vue
<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
```vue
<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](https://media.giphy.com/media/UQNzc6cn2qKeHkh7VZ/giphy.gif)

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

# References

* [Drag and drop javascript](https://www.w3schools.com/howto/howto_js_draggable.asp)
* [Vue named slots](https://es.vuejs.org/v2/guide/components-slots.html#Slots-Nombrados)
* [Vue refs](https://vuejs.org/v2/api/#ref)