vue3中使用draggable插件实现元素的拖拽,排序,克隆

vue2.x版本中利用draggable插件实现元素的拖拽,排序,克隆的例子网上有很多,这里不再赘述,有篇文章写得很不错,可以参考:https://blog.csdn.net/blue__k/article/details/120202902

但在vue3中,使用vue2.x中draggable的写法时会报错:Cannot read property ‘header’ of undefined

这个问题是draggable的版本不对,换为"vuedraggable": "^4.1.0"这个版本就好了

效果图

安装

npm i vuedraggable@4.1.0 --save
npm install sortablejs --save (拖拽组件依赖sortablejs ,如果项目没有安装sortablejs ,需要安装一下)

引入

import Draggable from 'vuedraggable'

关键代码

  <Draggable :list="list2" item-key="id" :animation="100" :sort='false' :group="{name: 'article',pull:'clone'}"  @end="end1" class="dragArea1">
      <template #item="{ element }"  >
        <div class="list-complete-item1">
          <div class="list-complete-item-handle2"> {{element.name}}</div>
        </div>
      </template>
    </Draggable>

注:vue2.x版本Draggable 组件中的配置项写法(:options="{group:{name: 'article',pull:'clone'}, sort: false}")在vue3中不起效,

vue3中需要将里面的参数单独进行配置,如::group="{name: 'article',pull:'clone'}"     :sort='false'  等

两个盒子之间的内容能够克隆,需要将两个group的name配置为一样,并在group中配置 pull:'clone'

如果不希望第二个盒子中的内容被拖到第一个盒子中,将第二个盒子中的pull改为空:pull:' '

部分Draggable API

 1  group: "name",  // or { name: "...", pull: [true, false, clone], put: [true, false, array] } name相同的组可以互相拖动
 2  sort: true,  // 内部排序列表
 3  delay: 0, // 以毫秒为单位定义排序何时开始。
 4  touchStartThreshold: 0, // px,在取消延迟拖动事件之前,点应该移动多少像素?
 5  disabled: false, // 如果设置为真,则禁用sortable。
 6  store: null,  // @see Store
 7  animation: 150,  // ms, 动画速度运动项目排序时,' 0 ' -没有动画。
 8  handle: ".my-handle",  // 在列表项中拖动句柄选择器。
 9  filter: ".ignore-elements",  // 不导致拖拽的选择器(字符串或函数)
10  preventOnFilter: true, // 调用“event.preventDefault()”时触发“filter”
11  draggable: ".item",  // 指定元素中的哪些项应该是可拖动的。
12  ghostClass: "sortable-ghost",  // 设置拖动元素的class的占位符的类名。
13  chosenClass: "sortable-chosen",  // 设置被选中的元素的class
14  dragClass: "sortable-drag",  //拖动元素的class。
15  dataIdAttr: 'data-id',
16  forceFallback: false,  // 忽略HTML5的DnD行为,并强制退出。(h5里有个属性也是拖动,这里是为了去掉H5拖动对这个的影响
17  fallbackClass: "sortable-fallback",  // 使用forceFallback时克隆的DOM元素的类名。
18  fallbackOnBody: false,  // 将克隆的DOM元素添加到文档的主体中。(默认放在被拖动元素的同级)
19  fallbackTolerance: 0, // 用像素指定鼠标在被视为拖拽之前应该移动的距离。
20  scroll: true, // or HTMLElement
21  scrollFn: function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { ... }
22  scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling.
23  scrollSpeed: 10, // px

全部代码

<template>
  <div class="dragList">
    <div class="dragList-list1">
      <h3 style="text-align:center">标签选择</h3>
      <Draggable :list="list2" item-key="id" :animation="100" :sort='false' :group="{name: 'article',pull:'clone'}"  @end="end1" class="dragArea1">
        <template #item="{ element }"  >
          <div class="list-complete-item1">
            <div class="list-complete-item-handle2"> {{element.name}}</div>
          </div>
        </template>
      </Draggable>
    </div>

    <div class="dragList-list2">
      <h3 style="text-align:center">拖动至此处</h3>
      <Draggable :list="list1" item-key="id"  :group="{name: 'article',pull:''}"  :disabled="false"  @start="start2" @end="end2" class="dragArea2" >
        <template #item="{ element,index }" >
          <div class="list-complete-item2">
            <div class="list-complete-item-handle">{{element.name}}</div>
            <div>
              <i class="el-icon-delete"  @click="handleDel(index, element.id)"></i>
            </div>
          </div>
        </template>
      </Draggable>
    </div>
  </div>
</template>

<script>
import {ref,reactive} from 'vue'
import Draggable from 'vuedraggable'

export default {
  components: {
    Draggable
  },
  setup() {
    const disabled = ref(false)
    const list1 = reactive([])
    const list2 = reactive(
      [
        {id: 1, name: '标签1'}, 
        {id: 2, name: '标签2'}, 
        {id: 3, name: '标签3'}, 
        {id: 4, name: '标签4'}, 
        {id: 5, name: '标签5'}, 
      ]
    )
    const end1 = (ev) => {
      console.log("拖动结束1",ev)
    }
    const start2 = (event) => {
      console.log("开始拖动",event)
    }
    const end2 = (ev) => {
      console.log("拖动结束2",ev)
    }
    const handleDel = (index, id) => {
      list1.splice(index, 1)
      let q = list2.find((value, index, arr) => {
        return value.id === id
      })
    }
    return {
      disabled,
      list1,
      list2,
      end1,
      start2,
      end2,
      handleDel
    }
  }
}
</script>

<style lang="scss"  scoped>
  .dragList{
    width: 500px;
    height:300px;
    padding: 20px;
  }
  .dragList-list1{
    width: 120px;
  }
  .list-complete-item1{
    cursor: pointer;
    font-size: 14px;
    padding: 0 12px;
    display: inline-block;
    margin-bottom: 10px;
    width: 100px;
    height: 50px;
    line-height: 50px;
    border: 1px solid #bfcbd9;
    transition: all 1s;
  }
  .dragArea1{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
  .dragList-list2{
    margin-top: 20px;
    height: 200px;
    border: 1px solid #8a8a8a;
  }
  .dragArea2{
    display: flex;
    align-items: center;
  }
  .list-complete-item2 {
    cursor: pointer;
    font-size: 14px;
    padding: 0 12px;
    display: inline-block;
    margin: 10px;
    width: 100px;
    line-height: 30px;
    text-align: center;
    border: 1px solid #bfcbd9;
    transition: all 1s;
  }
</style>
原文地址:https://www.cnblogs.com/lt66/p/15533021.html