手把手带你过一遍vuedraggable所有功能

lxf2023-07-17 22:10:01

vuedraggable

vue-draggable 使用 Vue.js 的组件来实现拖放(拖动)效果。vue2和vue3在使用方面的区别不大,能区分的我都尽可能做了标注,所以就不分两篇文章了。

安装

npm install vuedraggable --save # vue2
npm install vuedraggable@next --save # vue3

yarn add vuedraggable # vue2
yarn add vuedraggable@next # vue3

注册

基本用法只需要在 Vue 项目中导入vuedraggable组件并注册即可:

import draggable from 'vuedraggable'

export default {
  components: {
    draggable
  }
}

然后在模板中使用它:

<draggable v-model="list">
  <div v-for="element in list" class="list-element">{{element}}</div>
</draggable>
.list-element {
  padding: 10px;
  background: #eee;
}
data: {
  list: ['Item 1', 'Item 2', 'Item 3']
}

这将使这些列表项可拖拽排序。

示例代码

手把手带你过一遍vuedraggable所有功能

<template>
  <div class="row">
    <div class="col-2">
      <div class="form-group">
        <div
          class="btn-group-vertical buttons"
          role="group"
          aria-label="Basic example"
        >
          <button class="btn btn-secondary" @click="add">Add</button>
          <button class="btn btn-secondary" @click="replace">Replace</button>
        </div>

        <div class="form-check">
          <input
            id="disabled"
            type="checkbox"
            v-model="enabled"
            class="form-check-input"
          />
          <label class="form-check-label" for="disabled">DnD enabled</label>
        </div>
      </div>
    </div>

    <div class="col-6">
      <h3>Draggable {{ draggingInfo }}</h3>

      <draggable
        :list="list"
        :disabled="!enabled"
        class="list-group"
        ghost-class="ghost"
        :move="checkMove"
        @start="dragging = true"
        @end="dragging = false"
      >
        <div
          class="list-group-item"
          v-for="element in list"
          :key="element.name"
        >
          {{ element.name }}
        </div>
      </draggable>
    </div>

    <rawDisplayer class="col-3" :value="list" title="List" />
  </div>
</template>

<script>
import draggable from "@/vuedraggable";
let id = 1;
export default {
  name: "simple",
  display: "Simple",
  order: 0,
  components: {
    draggable
  },
  data() {
    return {
      enabled: true,
      list: [
        { name: "John", id: 0 },
        { name: "Joao", id: 1 },
        { name: "Jean", id: 2 }
      ],
      dragging: false
    };
  },
  computed: {
    draggingInfo() {
      return this.dragging ? "under drag" : "";
    }
  },
  methods: {
    add: function() {
      this.list.push({ name: "Juan " + id, id: id++ });
    },
    replace: function() {
      this.list = [{ name: "Edgard", id: id++ }];
    },
    checkMove: function(e) {
      window.console.log("Future index: " + e.draggedContext.futureIndex);
    }
  }
};
</script>
<style scoped>
.buttons {
  margin-top: 35px;
}

.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}
</style>

手把手带你过一遍vuedraggable所有功能

<template>
  <div class="row">
    <div class="col-3">
      <h3>Draggable 1</h3>
      <draggable
        class="list-group"
        :list="list1"
        group="people"
        @change="log"
        itemKey="name"
      >
        <template #item="{ element, index }">
          <div class="list-group-item">{{ element.name }} {{ index }}</div>
        </template>
      </draggable>
    </div>

    <div class="col-3">
      <h3>Draggable 2</h3>
      <draggable
        class="list-group"
        :list="list2"
        group="people"
        @change="log"
        itemKey="name"
      >
        <template #item="{ element, index }">
          <div class="list-group-item">{{ element.name }} {{ index }}</div>
        </template>
      </draggable>
    </div>

    <rawDisplayer class="col-3" :value="list1" title="List 1" />

    <rawDisplayer class="col-3" :value="list2" title="List 2" />
  </div>
</template>
<script>
import draggable from "@/vuedraggable";

export default {
  name: "two-lists",
  display: "Two Lists",
  order: 1,
  components: {
    draggable
  },
  data() {
    return {
      list1: [
        { name: "John", id: 1 },
        { name: "Joao", id: 2 },
        { name: "Jean", id: 3 },
        { name: "Gerard", id: 4 }
      ],
      list2: [
        { name: "Juan", id: 5 },
        { name: "Edgard", id: 6 },
        { name: "Johnson", id: 7 }
      ]
    };
  },
  methods: {
    add: function() {
      this.list.push({ name: "Juan" });
    },
    replace: function() {
      this.list = [{ name: "Edgard" }];
    },
    clone: function(el) {
      return {
        name: el.name + " cloned"
      };
    },
    log: function(evt) {
      window.console.log(evt);
    }
  }
};
</script>

手把手带你过一遍vuedraggable所有功能

<template>
  <div class="row">
    <div class="col-8">
      <h3>Draggable table</h3>

      <table class="table table-striped">
        <thead class="thead-dark">
          <tr>
            <th scope="col">Id</th>
            <th scope="col">Name</th>
            <th scope="col">Sport</th>
          </tr>
        </thead>
        <draggable v-model="list" tag="tbody" item-key="name">
          <template #item="{ element }">
            <tr>
              <td scope="row">{{ element.id }}</td>
              <td>{{ element.name }}</td>
              <td>{{ element.sport }}</td>
            </tr>
          </template>
        </draggable>
      </table>
    </div>

    <rawDisplayer class="col-3" :value="list" title="List" />
  </div>
</template>

<script>
import draggable from "@/vuedraggable";
export default {
  name: "table-example",
  display: "Table",
  order: 8,
  components: {
    draggable
  },
  data() {
    return {
      list: [
        { id: 1, name: "Abby", sport: "basket" },
        { id: 2, name: "Brooke", sport: "foot" },
        { id: 3, name: "Courtenay", sport: "volley" },
        { id: 4, name: "David", sport: "rugby" }
      ],
      dragging: false
    };
  }
};
</script>
<style scoped>
.buttons {
  margin-top: 35px;
}
</style>

Props

value(vue2) 或 modelValue(vue3)

type:Array
require:false 
default:null 
输入要拖动的组件数组。通常与内部元素v-for指令引用的相同数组。

<draggable v-model="myArray">

list 

type:Array 
require:false 
default:null
value属性的替代方案,list是一个与拖放同步的数组。 
主要区别是list属性使用splice方法更新数组,而value是不可变的。 
不要与value属性一起使用。

tag

type:String
require:false 
default:'div'
draggable组件作为外部元素创建的HTML节点类型,用于包含的插槽。
也可以将Vue组件的名称作为元素传递。在这种情况下,draggable属性将传递给创建的组件。
如果需要为创建的组件设置props或事件,请参见下面的componentData。示例:

<draggable tag="ul">
  <li>...</li>
</draggable>

这将渲染:

<ul>
  <li>...</li> 
</ul>

而不是默认的div。也可以传入组件:

<draggable tag="todo-list">
  <todo-item v-for="item in list" :text="item.text" /> 
</draggable>

这将渲染todo-list组件,并将draggable prop传递给它。

clone

type:Function
require:false
default:(original) => { return original;}
当clone选项为true时,在源组件上调用以克隆元素的函数。唯一的参数是要克隆的viewModel元素,返回值是其克隆版本
默认情况下,vue.draggable重用viewModel元素,所以如果要克隆或深度克隆它,必须使用这个钩子。示例:

clone: (original) => {
  let clone = JSON.parse(JSON.stringify(original))
  // 深度克隆并修改clone
  return clone 
}

这将在拖动操作期间深度克隆元素,而不是重新使用原始元素。你可以在这里执行任何自定义克隆逻辑。如果不提供clone prop,vue.draggable将简单地重新使用元素,而不是实际克隆它。所以,如果你的元素是Vue实例,或者您需要对其进行深度克隆,则必须提供clone prop。

move

type:Function
require:false
default:null
如果不为null,这个函数将以类似的方式调用Sortable onMove回调。返回false将取消拖动操作。

HTML:

<draggable :list="list" :move="checkMove">

javascript:

checkMove: function(evt){
    return (evt.draggedContext.element.name!=='apple');
}

componentData

type:Object
require:false
default:null
这个道具用于向通过声明的子组件传递额外信息。
值:
• props: 要传递给子组件的道具
• attrs: 要传递给子组件的属性
• on: 要在子组件中订阅的事件

<draggable tag="el-collapse" :list="list" :component-data="getComponentData()">
    <el-collapse-item v-for="e in list" :title="e.title" :name="e.name" :key="e.name">
        <div>{{e.description}}</div>
     </el-collapse-item>
</draggable>  
methods: {
    handleChange() {
      console.log('changed');
    },
    inputChanged(value) {
      this.activeNames = value;
    },
    getComponentData() {
      return {
        on: {
          change: this.handleChange,
          input: this.inputChanged
        },
        attrs:{
          wrap: true
        },
        props: {
          value: this.activeNames
        }
      };
    }
  }

componentData prop允许您将props,attrs和on传递给tag prop声明的子组件。这使您可以完全控制子组件及其与父组件draggable的交互。

其他sortable参数

从vue.draggable的版本2.19开始,可以直接将Sortable选项设置为vue.draggable的props。

{
    group: "name"// 可以简单理解为只要group相同,就可以互相拖拽
    sort: true// 在列表内排序   
    delay: 0, // 定义排序应开始的时间(以毫秒为单位)  
    delayOnTouchOnly: false, // 只在用户使用触摸时延迟  
    touchStartThreshold: 0, // px,在取消延迟的拖动事件之前,点应移动的像素数   
    disabled: false// 如果设置为true,则禁用sortable。  
    store: null// @see Store   
    animation: 150// ms,移动项目时的动画速度排序,`0` - 无动画   
    easing: "cubic-bezier(1, 0, 0, 1)", // 动画缓动。默认为null。请参阅  示例。  
    handle: ".my-handle"// 列表项内的拖动句柄选择器   
    filter: ".ignore-elements"// 不导致拖动的选择器(字符串或函数)   
    preventOnFilter: true, // 触发时调用`filter` `event.preventDefault()`  
    draggable: ".item"// 指定元素内哪些项目应可拖动    dataIdAttr: 'data-id', // `toArray()` 方法使用的HTML属性    ghostClass: "sortable-ghost",  // 拖放占位符的类名   
    chosenClass: "sortable-chosen"// 选定项目的类名   
    dragClass: "sortable-drag"// 拖动项目的类名     swapThreshold: 1, // 交换区域的阈值   
    invertSwap: false, // 如果设置为true,则始终使用反转的交换区域   
    invertedSwapThreshold: 1, // 反转的交换区域的阈值(默认情况下将设置为swapThreshold值)   
    direction: 'horizontal', // Sortable的方向(如果未给定,则会自动检测)     forceFallback: false,  // 忽略HTML5 DnD行为,强制回退   
    fallbackClass: "sortable-fallback"// 使用forceFallback时克隆的DOM元素的类名   
    fallbackOnBody: false// 将克隆的DOM元素附加到文档正文   
    fallbackTolerance: 0, // 指定鼠标应移动的像素数,才被视为拖动。     dragoverBubble: false,   
    removeCloneOnHide: true, // 隐藏时删除克隆元素,而不仅仅是隐藏它   
    emptyInsertThreshold: 5, // px,鼠标离空sortable的距离,以将拖动元素插入其中
}

支持kebab-case属性。例如,ghost-class属性将转换为ghostClass Sortable选项。
设置handle,sortable和group选项的示例:

<draggable
        v-model="list"
        handle=".handle"  
        group="name"  
        ghost-class="ghost"  
        :sort="false"  
        @change="log"  
      >  
</draggable>

EVENT

• 支持Sortable事件:
• startaddremoveupdateendchooseunchoosesortfilterclone
• 在Sortable.js触发onStart, onAdd, onRemove, onUpdate, onEnd, onChoose, onUnchoose, onSort, onClone时,events将以相同的参数进行调用。

HTML:

<draggable :list="list" @end="onEnd">
  •  change事件 当list prop不为空并且相应的数组因拖放操作而改变时,将触发change事件。此事件将以一个参数调用,其中包含以下属性之一:
    •  added: 包含添加到数组中的元素的信息
      •  newIndex: 添加的元素的索引
      •  element: 添加的元素
    •  removed: 包含从数组中移除的元素的信息
      •  oldIndex: 移除之前元素的索引
      •  element: 被移除的元素
    •  moved: 包含在数组中移动的元素的信息
      •  newIndex: 移动的元素的当前索引
      •  oldIndex: 移动的元素的旧索引
      •  element: 移动的元素change 事件在list prop发生变化时触发,并提供有关添加,删除或移动元素的详细信息。这使您可以在数组因拖放操作而改变时执行自定义逻辑。

Slots 

vue2限制:header或footer插槽无法与transition-group一起使用。

Header 

使用header插槽在vuedraggable组件内添加不可拖动元素。
重要提示:它应与draggable选项一起使用来标记可拖动元素。请注意,header插槽将始终位于默认插槽之前,而不考虑其在模板中的位置。例如:

<draggable v-model="myArray" draggable=".item"> 
    <div v-for="element in myArray" :key="element.id" class="item">
         {{element.name}} 
    </div>
    <button slot="header" @click="addPeople">Add</button>
</draggable>

Footer 

使用footer插槽在vuedraggable组件内添加不可拖动元素。重要提示:它应与draggable选项一起使用来标记可拖动元素。请注意,footer插槽将始终位于默认插槽之后,而不考虑其在模板中的位置。例如:

<draggable v-model="myArray" draggable=".item">  
    <div v-for="element in myArray" :key="element.id" class="item">  
         {{element.name}}  
    </div>
    <button slot="footer" @click="addPeople">Add</button>
</draggable>

从vue 2版本迁移:

  1. 使用item插槽代替默认插槽来显示元素
  2. 使用itemKey道具为项目提供键
<!-- vue 2 版本 -->
<draggable v-model="myArray">  
   <div v-for="element in myArray" :key="element.id">{{element.name}}</div>
</draggable>

<!-- vue 3 版本 -->
<draggable v-model="myArray" item-key="id">
  <template #item="{element}">
    <div>{{element.name}}</div>
   </template>
</draggable>
  1. 使用过渡时,现在应使用tag道具和componentData来创建过渡
<!-- vue 2 版本 -->
<draggable v-model="myArray">
    <transition-group name="fade">
        <div v-for="element in myArray" :key="element.id">
            {{element.name}}
        </div>
    </transition-group>
</draggable>

<!-- vue 3 版本 -->
<draggable v-model="myArray" tag="transition-group" :component-data="{name:'fade'}">
  <template #item="{element}">
    <div>{{element.name}}</div>
  </template>
</draggable>
本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!