2025/10/13

如何使用 vue3-draggable-next esm module

vue3-draggable-next 是 draggable 套件的 vue3 版本,預設在 dist 裡面,只提供 umd 及 commonjs module,如果要在 browser 裡面,透過 esm 的方式 import module,必須要先自己製作一個簡單的 esm js

vuedraggable.umd.js 檔案,就跟 vuedraggable.umd.min.js 放在同一個目錄

// 確保 UMD 先載入(它會掛在 window.vuedraggable)
import "./vuedraggable.umd.min.js";
// 把全域變數 export 出去,提供 ESM 的 default
export default window.vuedraggable;

然後在 html 裡面,先以 importmap 方式列出 import list

因為 draggable 有使用到 sortablejs,故這邊要先放到 import list

另外在下面的 module 裡面,要先將 Vue 及 Sortable 掛載到全域變數裡面,因為 draggable 是這樣直接呼叫 Vue 跟 Sortable,所以必須這樣掛載

    <script type="importmap">
    {
        "imports": {
            "vue": "../js/lib/vue-3.5.13/vue.esm-browser.prod.min.js",
            "vuedraggable": "../js/lib/vue3-draggable-next-4.1.4/vuedraggable.esm.js",
            "sortablejs": "../js/lib/sortable-1.15.6/sortable.esm.js"
        }
    }
    </script>

    <script type="module">
        import * as Vue from 'vue';
        window.Vue = Vue; // 讓 draggable UMD 找得到 Vue.defineComponent

        import Sortable from 'sortablejs';
        window.Sortable = Sortable;
    </script>

最後可製作 App

  <script type="module">
    import { createApp, reactive } from "vue";
    import Draggable from "vuedraggable";

    const state = reactive({
      rows: [
        { id: 1, name: "Item A" },
        { id: 2, name: "Item B" },
        { id: 3, name: "Item C" }
      ]
    });

    createApp({
      components: { Draggable },
      setup() {
        return { state };
      }
    }).mount("#app");
  </script>

html 的部分,可放在 tbody 裡面。

這邊注意 #item="{ element, index } #item 裡面,只能用 element, index,不能改成其他變數名稱。否則會一直遇到 undefined 物件的問題。

<div id="app">
    <table border="1">
      <thead>
        <tr>
          <th>Drag</th>
          <th>Name</th>
        </tr>
      </thead>
      <!-- draggable tbody -->
      <draggable
        tag="tbody"
        v-model="state.rows"
        handle=".drag-handle"
      >
        <template #item="{ element, index }">
          <tr :key="element.id">
            <td class="drag-handle" style="cursor: grab;">☰</td>
            <td>{{ element.name }}</td>
          </tr>
        </template>
      </draggable>
    </table>
    <pre>{{ state.rows }}</pre>
  </div>

vuedraggable 是 SortableJS 的包裝,所以大部分事件都對應到 SortableJS events,最常用的是:

  • @start 拖曳開始

  • @end 拖曳結束

  • @add 新元素被加入(跨清單)

  • @remove 元素被移除

  • @update 同一清單內順序改變

  • @change 綜合事件(新增、刪除、移動都會觸發)

實際上操作時

  • 拖曳開始到結束:會觸發 @start 與 @end

  • 順序有變動:會觸發 @update 和 @change

  • 跨清單拖曳:會觸發 @add 與 @remove