Vue.Draggable 是一款基于 Sortable.js 拖拽插件

# 一、特点

  1. 完全支持 Sortable.js 的功能支持触摸设备支持拖拽和选择文本智能自动滚动支持在不同列表之间拖拽没有 JQuery 依赖项
  2. 与视图模型同步刷新
  3. 与 Vue2 动画兼容
  4. 支持撤销操作
  5. 当需要完全控制时,可抛出所有的变化事件
  6. 与现有的 UI 组件兼容(比如 vuetify、element、vue material 等)

# 二、官方网站

https://github.com/SortableJS/Vue.Draggable

# 三、props

属性名称说明
value实现拖拽的 list 数组,不能直接使用,只能通过 v-model 使用,通常与 v-for 指令所用的数组相同
list与 value 功能相同,但不能与 v-model 共用
tagdraggable 渲染后在页面中展现出来的 HTML 节点类型,默认值为‘div’
clone当返回值为 true 时,拖拽的元素将被复制。参数为被拖拽的元素,返回值是其克隆版本、
move如果是空值,则将以类似于 Sortable 的 onMove 回调的方式调用此函数,返回 false 取消拖拽操作
componentData用来结合 UI 组件的,可以理解为代理了 UI 组件的定制信息
options列表配置项,Vue.Draggable 新版本废弃了 options 属性,建议使用 v-bind 属性作为配置项

options 配置项

img

# 四、Events

img

# 五、slot 插槽

Header

使用标题插槽在 vuedraggable 组件中添加不可拖动的元素。它应该与 draggable 选项一起使用来标记 draggable 元素。请注意,无论标题槽在模板中的位置如何,它总是被添加到默认槽之前。

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

Footer

使用页脚槽在 vuedraggable 组件中添加不可拖动的元素。它应该与 draggable 选项一起使用,以标记 draggable 元素。请注意,无论页脚槽在模板中的位置如何,它都将始终添加到默认槽之后。

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

注意:页眉或页脚插槽都不能与 tarnstion-group 一起使用。

# 六、安装方式

yarn

yarn add vuedraggableundefined

npm

npm install vuedraggableundefined

# 七、引入

import draggable from 'vuedraggable'javascript
// UMD 浏览器直接引用 JS 方式
<script src="https://www.itxst.com/package/vue/vue.min.js"></script>
<script src="https://www.itxst.com/package/sortable/Sortable.min.js"></script>
<script src="https://www.itxst.com/package/vuedraggable/vuedraggable.umd.min.js"></script>javascript

# 八、用法

# 1. 单列拖拽

<div id="app">
    <h3>单列拖拽</h3>
    <draggable 
      v-model="myArray" 
      chosen-class="chosen" 
      force-fallback="true" 
    >
      <transition-group>
        <div class="item" v-for="item in myArray" :key="item.id"></div>
      </transition-group>
    </draggable>
  </div>html

# 2. 多列拖拽

注意,vuedraggable 新版本废弃了 options 属性,建议使用 v-bind 属性作为配置项

多列拖拽示例代码使用了 options 属性,控制台抛出警告

img

北方城市 list 中增加 tag="ul",Elements 中可以看到其包裹标签为 ul,未加 tag 属性的南方城市则是默标签 div

img

<body style="padding:10px;">
  <div id="app">
    <h3>多列拖拽</h3>
    <div style="display: flex; width: 300px; justify-content: space-between;">
      <div>
        <h4>北方城市</h4>
        <draggable v-model="arr1" tag="ul" :options="dragOptions">
          <transition-group>
            <div class="item" v-for="item in arr1" :key="item.id"></div>
          </transition-group>
        </draggable>
      </div>
      <div>
        <h4>南方城市</h4>
        <draggable v-model="arr2" :options="dragOptions">
          <transition-group>
            <div class="item" v-for="item in arr2" :key="item.id"></div>
          </transition-group>
        </draggable>
      </div>
    </div>
  </div>
  <script>
    // 全局注册组件
    Vue.component('vuedraggable', window.vuedraggable)
    var app = new Vue({
      el: '#app',
      components: {
        vuedraggable: window.vuedraggable,//当前页面注册组件
      },
      data() {
        return {
          dragOptions: {
            group: 'city', //group相同时不同的list之间了可以拖动
            animation: '300'
          },
          // dragOptions1: {
          //   group: 'citys', //group不同时不同的list之间了不可拖动
          //   animation: '300'
          // },
          arr1: [{id: 1, name: '哈尔滨'},{id: 2, name: '吉林'},{id: 3, name: '长春'},{id: 4, name: '大连'}],
          arr2: [{id: 1, name: '贵州'},{id: 2, name: '昆明'},{id: 3, name: '北流'},{id: 4, name: '毕节'}],
        };
      }
    });
  </script>
</body>

# 3.clone、move

  • clone: :options="{group:{name: 'city',pull:'clone'},sort: true}",表示允许克隆被拖动的元素
  • move:获取当前拖动元素的对象、控制某个 / 些元素不允许被拖拽
  • end:拖拽事件结束,用来判断是否已经存在对象

左侧的 draggable 标签添加了 options 配置项(新版本为 v-bind)

{group:{name: 'city',pull:'clone'},sort: true}: name 与右侧 group 名称一致,可相互拖拽, pull:‘clone’ 表示进行克隆拖动操作, sort: true 表示拖动时允许进行排序操作

<body style="padding:10px;">
  <div id="app">
    <h3>clone</h3>
    <div style="display: flex; width: 300px; justify-content: space-between;">
      <draggable v-model="arr1" :options="{group:{name: 'city',pull:'clone'},sort: true}" :move="onMove" @end="end1">
        <transition-group>
          <div class="item" v-for="item in arr1" :key="item.id"></div>
        </transition-group>
      </draggable>
      <draggable v-model="arr2" group="city" v-bind="dragOptions" @end="end2">
        <transition-group>
          <div class="item" v-for="item in arr2" :key="item.id"></div>
        </transition-group>
      </draggable>
    </div>
  </div>
  <script>
    // 全局注册组件
    Vue.component('vuedraggable', window.vuedraggable)
    var app = new Vue({
      el: '#app',
      components: {
        vuedraggable: window.vuedraggable,//当前页面注册组件
      },
      data() {
        return {
          dragOptions: {
            animation: '300'
          },
          arr1: [{id: 1, name: '西瓜'},{id: 2, name: '草莓'},{id: 3, name: '葡萄'},{id: 4, name: '榴莲'}],
          arr2: [{id: 11, name: '胡萝卜'},{id: 22, name: '西红柿'}],
        };
      },
      methods: {
        onMove(e,originalEvent) {
          if(e.draggedContext.element.id == 1) return false // 不允许拖拽
          if(e.relatedContext.element.id == 4) return false // 不允许停靠
          return true
        },
        end1(e) {
          console.log(e,'111');
        },
        end2(e) {
          console.log(e,'222');
        }
      }
    });
  </script>
</body>