2020年12月11日 星期五

Vue 使用 vue-drag-drop 完成 Drag & Drop

 Drag & Drop 就是網站的拖曳效果,今天要達成的目標就是有兩個區域A及B,裡面有資料,

把資料拖曳到任一個區域都可以在該區域新增資料,並刪除原區域內的資料。透過 HTML 的

拖放 API,設定多而且 DOM 的長度可觀。


原理簡略的說: Drag 是可拖動的物件,Drop 是可放置的區域,透過今天使用的套件,可以使 

Drag 帶著資料去觸發 Drop 的事件,達成放置資料或其他操作。


import VueDragDrop from 'vue-drag-drop';
Vue.use(VueDragDrop);

先 import 跟 use,官方文件有一個範例,比較接近 Basic list support ,不過這個範例有幾個需要

改變的地方,第一個是兩個區域不能總貼在一起,再來是如何讓排列順序是有序的,範例中

使用 .sort 進行陣列重排,我希望跟積木一樣可以使用者將資料移到那就把資料放在那。


<template>
<div>
  <div class="container">
    <div class="row">
      <div class="col-3">
        <div class="drop">
          <div v-for="(item, i) in testList[0]" :key="i">
            <drop @drop="drop1(item, ...arguments)">
              <drag class="drag"
                :transfer-data="{ item: item, list: testList[0], example: 'lists' }">
                {{ item }}
              </drag>
            </drop>
          </div>
        </div>
      </div>
      <div class="col-9">
        <div class="drop">
          <div v-for="(item, i) in testList[1]" :key="i">
            <drop @drop="drop2(item, ...arguments)">
              <drag class="drag"
                :transfer-data="{ item: item, list: testList[1], example: 'lists' }">
                {{ item }}
              </drag>
            </drop>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
</template>


template 使用 bootstrap 進行簡單的排版,左右有兩個框,分別放置 testList[0] 跟 testList[1] 的

陣列,裡面的資料稍微用 CSS 讓資料變清楚,不同的區域基本方法是相同只是觸發區域

不一樣,可以看到每個 item 有一個 drop 讓 drag 可被放上去,也有 drag 讓 item 可被拖曳,

<drag> 以及<drop> 標籤就是 vue-drag-drop 套件替你省下了無數的 DOM 指令。


@drop(item, ...arguments) 方法是官方推薦的,表示當 drag 被放進 drop 時觸發的方法,第一個參數是 drop 所在的元素,第二個參數是 drag 額外帶的 data。 drag攜帶資料的方法:

<drag class="drag"
                :transfer-data="{ item: item, list: testList[1], example: 'lists' }">

利用 :transfer-data,攜帶 drag 的 item ,所在的 array ,或其他。


最後處理方法,只要清楚 drag 在哪? drop 在哪? 那哪裡應該放置新資料或刪除已移動的資料就是小事了。splice(索引, 從索引之後刪除幾項, 加入的資料)。


methods: {
    drop1 (item, data) {
      const testlist = data.list
      // drag 所在的陣列
      this.testList[0].splice(this.testList[0].indexOf(item), 0, data.item)
      // 接收的 drop 新增 item
      testlist.splice(testlist.indexOf(data.item), 1)
      // 刪除原陣列的 item
    },
    drop2 (item, data) {
      const testlist = data.list
      // drag 所在的陣列
      this.testList[1].splice(this.testList[1].indexOf(item), 0, data.item)
      // 接收的 drop 新增 item
      testlist.splice(testlist.indexOf(data.item), 1)
      // 刪除原陣列的 item
    }
  }


成品圖:兩個區域為了清晰加了一個固定大小的框,所以如果全部資料都在同一個區域會爆版,自行調整 CSS 即可。




參考資料:

MDN

vue-drag-drop 文件

沒有留言:

張貼留言