몽땅뚝딱 개발자

[Vue.js] Drag & Drop / 드래그 앤 드롭 본문

Development/Vue.js

[Vue.js] Drag & Drop / 드래그 앤 드롭

레오나르도 다빈츠 2022. 2. 5. 16:32

 

 

trello를 쓰면서 항상 궁금했던 Drag & Drop...

vue-draggable도 있지만 직접 만들어보려고 츄라이해보았다. (🤗)

 

요소를 클릭한 상태에서 요소를 올렸을 때, 요소 간 간격이 벌어지거나 부드럽게 떨어지는 CSS는 추후에 추가해보려한다.

 

 

 


 

 

 

📄 HTML

v-for로 요소를 감싸는 <div>와 드래그가 가능한 요소를 뿌린다.

드래그가 가능한 요소들을 감싸는 곳(여기서는 class명이 'col'인 <div>)에는 @drop 이벤트를 추가한다. 이 때, @dragenter와 @dragover에는 기본 동작을 막는 .prevent를 적용해주어야 @drop이 실행된다.

드래그가 가능해야하는 요소에는 draggable="true"를 추가해준다.

<div>
  <div v-for="(item, idx) in lists" :key="item.id">
    <div class="col"
         @drop.prevent="onDrop($event, idx)"
         @dragenter.prevent
         @dragover.prevent
    >
      <div v-for="(numItem, idx) in item.numberList" :key="idx"
           class="box"
           @dragstart="startDrag($event, numItem, item.id)"
           draggable="true"
      >
        <p>{{ numItem.content }}</p>
      </div>
    </div>
  </div>
</div>

 

 

📄 JS

<script>
export default {
  name: "MoveTest",
  data() {
    return {
      lists: [
        {
          id: 1,
          numberList: [ { content: 1 }, { content: 2 } ]
        },
        {
          id: 2,
          numberList: [ {content: 3}, {content: 4}, {content: 5}, {content: 6} ]
        },
        {
          id: 3,
          numberList: [ {content: 7}, {content: 8}, {content: 9} ]
        }
      ]
    };
  },
  methods: {
    startDrag(event, item) {
      event.dataTransfer.dropEffect = "move"
      event.dataTransfer.effectAllowed = "move"
      event.dataTransfer.setData("selectedItem", item.content)
    },
    onDrop(event, colNum) {
      const selectedItem = Number(event.dataTransfer.getData("selectedItem"))

      // 리스트에서 선택된 아이템과 같은 content 값을 가진 요소를 찾아 index를 반환한다.
      let targetIdx
      let targetItem
      this.lists.forEach((obj, index) => {
        obj.numberList.forEach((ob) => {
          if(ob.content === selectedItem) {
            targetIdx = index
            targetItem = ob
          }
        })
      })

      // drop이 된 <div> index(=colNum)를 받아 리스트에 추가한다. 
      // 기존 리스트에서는 요소를 삭제한다. (splice() 사용)
      this.lists[colNum].numberList.push(targetItem)
      this.lists[targetIdx].numberList.splice(this.lists[targetIdx].numberList.indexOf(targetItem), 1)
    },
  },
};
</script>

 

 

📄 CSS

<style lang="scss">
.playground {
  display: flex;

  .col {
    display: flex;
    height: 500px;
    width: 150px;
    background-color: #fff;
    border: 1px solid lightgrey;
    margin-left: 5px;
    flex-direction: column;
    align-items: center;
    border-radius: 8px;

    .box {
      width: 130px;
      height: 50px;
      background-color: #7b71b7;
      margin-top: 10px;
      border-radius: 5px;

      p {
        text-align: center;
        line-height: 50px;
        color: white;
      }
    }
  }
}
</style>

 

 

 


개인적으로 공부한 내용을 정리하는 블로그로
잘못된 개념을 게시하지않도록 주의하고 있으나 오류가 있을 수 있습니다.

 

 

Comments