Vue.Draggable学习总结

Draggable为基于Sortable.js的vue组件,用以实现拖拽功能。

特性

支持触摸设备
支持拖拽和选择文本
支持智能滚动
支持不同列表之间的拖拽
不以jQuery为基础
和视图模型同步刷新
和vue2的国度动画兼容
支持撤销操作
当需要完全控制时,可以抛出所有变化
可以和现有的UI组件兼容

安装

npm install vuedraggable

引入

import draggable from 'vuedraggable'

官方例子:
hello.vue

<template>
  <div class="fluid container">
    <div class="form-group form-group-lg panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Sortable control</h3>
      </div>
      <div class="panel-body">
        <div class="checkbox">
          <label><input type="checkbox" v-model="editable">Enable drag and drop</label>
        </div>
        <button type="button" class="btn btn-default" @click="orderList">Sort by original order</button>
      </div>
    </div>

    <div class="col-md-3">
      <draggable class="list-group" element="ul" v-model="list" :options="dragOptions" :move="onMove" @start="isDragging=true" @end="isDragging=false">
        <transition-group type="transition" :name="'flip-list'">
          <li class="list-group-item" v-for="element in list" :key="element.order">
            <i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
            {{element.name}}
            <span class="badge">{{element.order}}</span>
          </li>
        </transition-group>
      </draggable>
    </div>

    <div class="col-md-3">
      <draggable element="span" v-model="list2" :options="dragOptions" :move="onMove">
        <transition-group name="no" class="list-group" tag="ul">
          <li class="list-group-item" v-for="element in list2" :key="element.order">
            <i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
            {{element.name}}
            <span class="badge">{{element.order}}</span>
          </li>
        </transition-group>
      </draggable>
    </div>

    <div class="list-group col-md-3">
      <pre>{{listString}}</pre>
    </div>
    <div class="list-group col-md-3">
      <pre>{{list2String}}</pre>
    </div>
  </div>
</template>

<script>
import draggable from "vuedraggable";
const message = [
  "vue.draggable",
  "draggable",
  "component",
  "for",
  "vue.js 2.0",
  "based",
  "on",
  "Sortablejs"
];

export default {
  name: "hello",
  components: {
    draggable
  },
  data() {
    return {
      list: message.map((name, index) => {
        return { name, order: index + 1, fixed: false };
      }),
      list2: [],
      editable: true,
      isDragging: false,
      delayedDragging: false
    };
  },
  methods: {
    orderList() {
      this.list = this.list.sort((one, two) => {
        return one.order - two.order;
      });
    },
    onMove({ relatedContext, draggedContext }) {
      const relatedElement = relatedContext.element;
      const draggedElement = draggedContext.element;
      return (
        (!relatedElement || !relatedElement.fixed) && !draggedElement.fixed
      );
    }
  },
  computed: {
    dragOptions() {
      return {
        animation: 0,
        group: "description",
        disabled: !this.editable,
        ghostClass: "ghost"
      };
    },
    listString() {
      return JSON.stringify(this.list, null, 2);
    },
    list2String() {
      return JSON.stringify(this.list2, null, 2);
    }
  },
  watch: {
    isDragging(newValue) {
      if (newValue) {
        this.delayedDragging = true;
        return;
      }
      this.$nextTick(() => {
        this.delayedDragging = false;
      });
    }
  }
};
</script>

<style>
.flip-list-move {
  transition: transform 0.5s;
}

.no-move {
  transition: transform 0s;
}

.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}

.list-group {
  min-height: 20px;
}

.list-group-item {
  cursor: move;
}

.list-group-item i {
  cursor: pointer;
}
</style>

main.js

import Vue from "vue";
import App from "./App.vue";
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/less/font-awesome.less";

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

属性和方法说明

属性

value

Array,非必须,默认为null

用于实现拖拽的list,通常和内部v-for循环的数组为同一数组。
最好使用vuex来实现传入。
不是直接使用,而是通过v-model引入。

<draggable v-model="myArray">
list

Array,非必须,默认为null

就是value的替代品。
和v-model不能共用
从表现上没有看出不同

element

String,默认div

就是<draggable>标签在渲染后展现出来的标签类型
也是包含拖动列表和插槽的外部标签
可以用来兼容UI组件

options

Object

配置项
group: string or array 分组用的,同一组的不同list可以相互拖动
sort: boolean 定义是否可以拖拽
delay:number 定义鼠标选中列表单元可以开始拖动的延迟时间
touchStartThreshold:number (不清楚)
disabled: boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能
store:
animation: umber 单位:ms 动画时间
handle: selector 格式为简单css选择器的字符串,使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动
filter: selector 格式为简单css选择器的字符串,定义哪些列表单元不能进行拖放,可设置为多个选择器,中间用“,”分隔
preventOnFilter: 当拖动filter时是否触发event.preventDefault()默认触发
draggable: selector 格式为简单css选择器的字符串,定义哪些列表单元可以进行拖放
ghostClass: selector 格式为简单css选择器的字符串,当拖动列表单元时会生成一个副本作为影子单元来模拟被拖动单元排序的情况,此配置项就是来给这个影子单元添加一个class,我们可以通过这种方式来给影子元素进行编辑样式
chosenClass: selector 格式为简单css选择器的字符串,目标被选中时添加
dragClass:selector 格式为简单css选择器的字符串,目标拖动过程中添加
forceFallback: boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等
fallbackClass: string 当forceFallback设置为true时,拖放过程中鼠标附着单元的样式
dataIdAttr: data-id
scroll:boolean当排序的容器是个可滚动的区域,拖放可以引起区域滚动
scrollFn:function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { … } 用于自定义滚动条的适配
scrollSensitivity: number 就是鼠标靠近边缘多远开始滚动默认30
scrollSpeed: number 滚动速度

函数配置

setData: 设置值时的回调函数
onChoose: 选择单元时的回调函数
onStart: 开始拖动时的回调函数
onEnd: 拖动结束时的回调函数
onAdd: 添加单元时的回调函数
onUpdate: 排序发生变化时的回调函数
onRemove: 单元被移动到另一个列表时的回调函数
onFilter: 尝试选择一个被filter过滤的单元的回调函数
onMove: 移动单元时的回调函数
onClone: clone时的回调函数
以上函数对象的属性:
to: 移动到的列表的容器
from:来源列表容器
item: 被移动的单元
clone: 副本的单元
oldIndex:移动前的序号
newIndex:移动后的序号

clone

function,默认值: 无处理

这一项要配合着options的group项的pull项处理,当pull:'clone时的拖拽的回调函数’
就是克隆的意思。
可以理解为正常的拖拽变成了复制。
当为true时克隆

move

function,默认值:null

就是拖拽项时调用的函数
用来确定拖拽是否生效
返回null时可以生效
可以通过函数判断
有一个参数:evt
evt为object
draggedContext: 被拖拽元素的上下文
index:拖拽元素的指针
element: 拖拽数据本身
futureIndex: 拖动后的index
relatedContext: 拖入区域的上下文
index: 目标元素的index
element:目标数据本身
list: 拖入的列表
component:目标组件

<draggable element="ul" v-model="list" :move='allow'>
...
methods: {
  allow(evt) {
    console.log(evt.draggedContext.index)
    console.log(evt.draggedContext.element)
    console.log(evt.draggedContext.futureIndex)
    console.log(evt.relatedContext.index)
    console.log(evt.relatedContext.element)
    console.log(evt.relatedContext.list)
    console.log(evt.relatedContext.component)
    return (evt.draggedContext.element.name!== 'b')
  }
}

componentData

Object,默认值:null

用来结合UI组件的,可以理解为代理了UI组件的定制信息
包含两项:props和on
props用来代理UI组件需要绑定的属性(:)
on用来代理UI组件需要绑定的事件(@)

<draggable element="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
      },
      props: {
        value: this.activeNames
      }
    };
  }
}

事件

有以下几种
start, add, remove, update, end, choose, sort, filter, clone

参数带有如下属性:

add: 包含被添加到列表的元素
newIndex: 添加后的新索引
element: 被添加的元素
removed: 从列表中移除的元素
oldIndex: 移除前的索引
element: 被移除的元素
moved:内部移动的
newIndex: 改变后的索引
oldIndex: 改变前的索引
element: 被移动的元素
插槽
提供一个footer插槽,在排序列表之下。
永远位于最下方。

<draggable v-model="myArray" :options="{draggable:'.item'}">
    <div v-for="element in myArray" :key="element.id" class="item">
        {{element.name}}
    </div>
    <button slot="footer" @click="addPeople">Add</button>
</draggable>
500575091.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270