Skip to content

vuedraggable

vuedraggable 是一个基于 Sortable.js 的 Vue 组件,用于实现拖拽和排序功能。它可以让你在 Vue 应用中轻松地实现拖拽排序,并提供了丰富的配置选项和事件来控制拖拽行为。

Sortable.js 是一个轻量级的 JS 库,用于实现拖拽排序功能。它支持 HTML5 的拖拽 API,并提供了丰富的选项和事件,可以轻松地在网页中实现拖拽排序、拖拽交换等功能。Vue.Draggable 是基于 Sortable.js 构建的,用于在 Vue 应用中实现这些功能。

Sortable.js 的特点:

  1. 轻量级:Sortable.js 非常轻量,核心库只有几千字节。
  2. 高性能:利用现代浏览器的 HTML5 拖拽 API,提供高性能的拖拽体验。
  3. 多样的选项:提供丰富的选项和回调函数,可以自定义拖拽行为。
  4. 多种场景:支持多种拖拽场景,包括列表排序、网格布局、分组拖拽等。
  5. 与框架集成:容易与主流前端框架集成,如 Vue、React、Angular 等。

基本使用

首先安装这个库:

bash
npm install vuedraggable@4.0.0

注意在安装的时候,一定要指定安装的版本为 4.0.0

安装后可以从这个库中导入一个组件

vue
<template>
  <draggable
    v-model="myArray"
    group="people"
    @start="drag = true"
    @end="drag = false"
    itemKey="id"
  >
    <template #item="{ element }">
      <div class="task">{{ element.name }}</div>
    </template>
  </draggable>
</template>

<script setup>
import draggable from "vuedraggable";
</script>

这是 vuedraggable 的一个标准用法。

  1. v-model="myArray":数组包含了需要拖拽排序的元素。
  2. group="people":group 属性用于配置分组,相同 group 名称的 draggable 实例之间允许相互拖拽元素。
  3. @start="drag=true":当拖拽操作开始时触发,这里将 drag 变量设置为 true,这可以用于在拖拽开始时触发一些行为,比如改变样式或显示一些提示。
  4. @end="drag=false":当拖拽操作结束时触发,这里将 drag 变量设置为 false

实战案例

一个“未完成”列表和一个“已完成”列表,两个列表之间的项目可以自由拖动。

vue
<template>
  <div id="app">
    <h1>待办事项</h1>
    <div class="newTask-container">
      <input
        type="text"
        v-model="newItem"
        class="newTaskInput"
        placeholder="添加新任务"
      />
      <button @click="addNewTask">添加新任务</button>
    </div>
    <div class="list-container">
      <div>
        <h2>未完成</h2>
        <!-- 任务:显示未完成的任务,并且可以自由拖拽 -->

        <!-- 这是普通的显示列表内容 -->
        <!-- <div v-for="item in list1" :key="item.id" class="task">
          {{ item.text }}
        </div> -->

        <!-- 使用vuedraggable插件实现拖拽 -->
        <draggable
          v-model="list1"
          group="tasks"
          @start="drag = true"
          @end="endHandle"
          itemKey="id"
        >
          <template #item="{ element }">
            <TransitionGroup name="fade" tag="div">
              <div class="task" :key="element.id">{{ element.text }}</div>
            </TransitionGroup>
          </template>
        </draggable>
      </div>
      <div>
        <h2>已完成</h2>
        <!-- 任务:显示已完成的任务,并且可以自由拖拽 -->
        <!-- <div v-for="item in list2" :key="item.id" class="task">
          {{ item.text }}
        </div> -->

        <!-- 使用vuedraggable插件实现拖拽 -->
        <draggable
          v-model="list2"
          group="tasks"
          @start="drag = true"
          @end="endHandle"
          itemKey="id"
        >
          <template #item="{ element }">
            <TransitionGroup name="fade" tag="div">
              <div class="task" :key="element.id">{{ element.text }}</div>
            </TransitionGroup>
          </template>
        </draggable>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";
import draggable from "vuedraggable";

// 未完成列表
const list1 = ref([
  { id: 1, text: "学习Vue" },
  { id: 2, text: "书写Draggable案例" },
  { id: 3, text: "看10页书" },
]);

// 已完成列表
const list2 = ref([
  { id: 4, text: "玩游戏" },
  { id: 5, text: "听音乐" },
  { id: 6, text: "看电影" },
]);

const newItem = ref("");

const addNewTask = () => {
  if (!newItem.value) return;
  list1.value.push({ id: Date.now(), text: newItem.value });
  newItem.value = "";
};

const endHandle = () => {
  console.log("拖拽结束");
};
</script>

<style scoped>
body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  margin: 0;
  padding: 0;
}

#app {
  max-width: 800px;
  margin: 50px auto;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
  text-align: center;
  color: #333;
}

.newTask-container {
  display: flex;
  width: 60%;
  justify-content: space-between;
  margin: 20px auto;
}

.newTask-container input {
  padding: 10px;
  width: 70%;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.newTask-container button {
  padding: 10px 20px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.list-container {
  display: flex;
  justify-content: space-around;
  margin-top: 20px;
}

h2 {
  text-align: center;
  color: #666;
  margin-bottom: 10px;
}

.task {
  padding: 15px;
  margin: 5px 0;
  background-color: #42b983;
  color: white;
  border-radius: 4px;
  cursor: move;
  transition: background-color 0.3s, transform 0.3s;
}

.task:hover {
  background-color: #369870;
  transform: scale(1.02);
}

/* 过渡相关的样式 */
.fade-enter-active,
.fade-leave-active {
  transition: all 0.5s;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
</style>

-EOF-

MIT License