vue 使用 vuedraggable插件实现拖拽功能

6,167 阅读4分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

前言

Vue.Draggable是一款基于Sortable.js实现的vue拖拽插件。支持移动设备、拖拽和选择文本、智能滚动,可以在不同列表间拖拽、不依赖jQuery为基础、vue 2过渡动画兼容、支持撤销操作,总之是一款非常优秀的vue拖拽组件。本篇将介绍如何搭建环境及简单的例子,使用起来特别简单对被拖拽元素也没有CSS样式的特殊要求。

NPM或yarn安装方式

yarn add vuedraggable
npm i -S vuedraggable

属性说明

如果下面的属性说明未能完全看明白,请访问非vue版 sortable.js里面有更详细的例子。

属性名称说明
group:group= "name",相同的组之间可以相互拖拽
sort:sort= "true",是否开启内部排序,如果设置为false,它所在组无法排序,在其他组可以拖动排序
delay:delay= "0", 鼠标按下后多久可以拖拽
touchStartThreshold鼠标移动多少px才能拖动元素
disabled:disabled= "true",是否启用拖拽组件
animation拖动时的动画效果,还是很酷的,数字类型。如设置animation=1000表示1秒过渡动画效果
handle:handle=".mover" 只有当鼠标移动到css为mover类的元素上才能拖动
filter:filter=".unmover" 设置了unmover样式的元素不允许拖动
draggable:draggable=".item" 那些元素是可以被拖动的
ghostClass:ghostClass="ghostClass" 设置拖动元素的占位符类名,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
chosenClass:ghostClass="hostClass" 被选中目标的样式,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
dragClass:dragClass="dragClass"拖动元素的样式,你的自定义样式可能需要加!important才能生效,并把forceFallback属性设置成true
dataIdAttrdataIdAttr: 'data-id'
forceFallback默认false,忽略HTML5的拖拽行为,因为h5里有个属性也是可以拖动,你要自定义ghostClass chosenClass dragClass样式时,建议forceFallback设置为true
fallbackClass默认false,克隆的DOM元素的类名
allbackOnBody默认false,克隆的元素添加到文档的body中
fallbackTolerance拖拽之前应该移动的px
scroll默认true,有滚动区域是否允许拖拽
scrollFn滚动回调函数
scrollSensitivity距离滚动区域多远时,滚动滚动条
scrollSpeed滚动速度

事件列表

事件名称说明
start开始拖动时触发的事件
add从一个数组拖拽到另外一个数组时触发的事件
remove移除事件
update拖拽变换位置时触发的事件
end拖拽完成时的事件
choose鼠标点击选中要拖拽元素时的事件
unchoose选中后松开鼠标的事件
sort位置变化时的事件
clone从一个数组拖拽到另外一个数组时触发的事件和add不同,clone是复制了数组元素

我们的需求

原文档这块写的不清晰

image.png

  • 从A区间可以往B区拖动
  • A区的数据不删除
  • A区不能往A区拖动
  • A区的数据需要经过处理,才能放到B

如何达到上面的需求呢,这里要用到 自定义控制

vue.draggable move 自定义控制那些元素可以拖拽或不允许拖拽并控制是否允许停靠

//move回调方法
onMove(e,originalEvent){ 
         console.log(e);
         console.log(originalEvent);
         //false表示阻止拖拽
         return true;
  },  
  
/** e对象结构注释
draggedContext: 被拖拽的元素
      index: 被拖拽的元素的序号
      element: 被拖拽的元素对应的对象
      futureIndex: 预期位置、目标位置
relatedContext: 将停靠的对象
      index: 目标停靠对象的序号
      element: 目标的元素对应的对象
      list:  目标数组
      component: 将停靠的vue组件对象
**/

具体代码 A 拖拽组件配置

<vuedraggable
          v-model="arr1"
          :move="onMove"
          :options="{ group: { name: 'site', pull: 'clone' }, sort: true }"
          animation="300"
          drag-class="dragClass"
          ghost-class="ghostClass"
          chosen-class="chosenClass"
          @add="onAdd"
          @start="onStart"
          @end="onEnd"
        >
          <transition-group>
            <div v-for="item in arr1" :key="item.id" class="item">
              <img
                style="margin-bottom: 20px"
                src="https://img3.bitautoimg.com/autoalbum/files/20190416/918/0333509185_6.png"
                width="100px"
              />
              {{ item.name }}
            </div>
          </transition-group>
        </vuedraggable>

B拖拽组件配置

<vuedraggable
      v-model="arr2"
      group="site"
      animation="300"
      @add="onAdd"
      @start="onStart"
      @end="onEnd"
    >
      <transition-group>
        <div v-for="item in arr2" :key="item.id" class="item">
          {{ item.name }}
        </div>
      </transition-group>
</vuedraggable>

方法

methods: {
    onMove(e, originalEvent) {
      console.log(e, originalEvent, 'onMove')
      // 停靠对象 如果停靠对象是A区,就拒绝掉
      if (e.relatedContext.element.isConfig) return false

      // 拖拽对象
      // if (e.draggedContext.element.isConfig) return false
      return true
    }
}

以及data数据

  data() {
    return {
      arr1: [
        { id: 1, isConfig: true, name: 'www.itxst.com' },
        { id: 2, isConfig: true, name: 'www.jd.com' },
        { id: 3, isConfig: true, name: 'www.baidu.com' },
        { id: 4, isConfig: true, name: 'www.taobao.com' },
      ],
      arr2: [
        { id: 5, name: 'www.google.com' },
        { id: 6, name: 'www.msn.com' },
        { id: 7, name: 'www.ebay.com' },
        { id: 8, name: 'www.yahoo.com' },
      ],
    }
  },

PS:注意事项

  • A区组件添加 :options="{ group: { name: 'site', pull: 'clone' }, sort: true }"

其中的 name:site 指向B组件的group属性,表示clone到B 但是A不删除

  • 在move方法中 e.relatedContext.element 代表停靠的数据对象,也就是B的元素,e.draggedContext.element 被拖拽的元素对象。 也就是A元素。然后开始处理A的数据