拖拽效果有比较成熟的组件库了: Vue-Draggable

它是基于Sortable.js实现的,适用vue项目,可以在pc端使用也可以在移动端使用

官网地址: GitHub - SortableJS/Vue.Draggable: Vue drag-and-drop component based on Sortable.js 线上演示地址: sortablejs.github.io/Vue.Draggab…

  • 支持可触摸设备
  • 支持拖动选取和文本选取
  • 支持在不同列表间拖拽
  • 没有jQuery依赖项
  • 拖拽可撤销
  • 拖拽有过渡动画
  • 首先进入你的vue项目,引入组件库

    npm i vuedraggable -S

    这第一步就报错的估计就只有我了,node-module包删删引引好多次,就是不行。

    报错就是让我去看一个debug文件:nodejs\node_cache_logs\2022-06-29T04_30_02_307Z-debug-0.log

    实不相瞒,真看不懂。

    求助度娘,说是需要清除npm的缓存,这里也有两个槽点。唉,接着看吧:

    npm cache clean --force

    上面指令执行后没一点用,还是出错,又启用了下面这个指令:

    npm cache verify

    你们自己看着用吧(如果和我一样第一步就出错的😅)

    如果你项目使用这个拖拽功能比较多,就全局注册。

    单个页面使用的话就局部注册好了:

    ① import draggable from 'vuedraggable'

    ② export default { components: { draggable,

    可要注意了,组件注册需要两步,这里就不要踩坑啦!!

    <draggable v-model="myArray"  @start="onStart" @end="onEnd">
    	<div class="item" v-for="element in myArray" :key="element.id">{{element.name}}</div>
    </draggable>
    myArray: [{ people: 'cn', id: 1, name: 'www.itxst.com' },
              { people: 'cn', id: 2, name: 'www.baidu.com' },
              { people: 'cn', id: 3, name: 'www.taobao.com' },
              { people: 'us', id: 4, name: 'www.google.com' }
    
    进阶使用—带过渡效果
    <draggable v-model="myArray"  @start="onStart" @end="onEnd">
        <transition-group>
         <div class="item" v-for="item in myArray" :key="item.id">{{item.name}}</div>
        </transition-group>
    </draggable>
    

    1. list 作为value属性的替代方法,list 是通过拖放进行同步的数组。

    主要区别在于list属性由可拖动组件使用拼接方法更新,而value属性是不可变的。

    ❗需要注意的是:不要与value一起使用。

    2. tag

    配置该属性后,draggable标签将会作为指定标签渲染。

    也就是说,tag是用来设置节点类型的。

    默认值是:div,接收字符串类型的数据。

    3.group

    这个是实现不同组之间相互拖拽的关键属性。

    有两种使用方式:

    ①字符串类型

    直接给两组配置相同的组名,eg:group:'course'

    ②对象类型

    name:设置组名

    pull:true/false是否允许拖出当前组

    put:true/false是否允许拖入当前组

    group:{
        name:'course',//组名为itxst
        pull: true|false| 'clone'|array|function,//是否允许拖出当前组
        put:true|false|array|function,//是否允许拖入当前组
    

    常用的也就这些,其他配置项没有深入了解就不在这里介绍了,有需要请移步官网哦~

    不过需要提醒的是:

    ✨如果需要配置clone,disable,sort等属性时,切记放在options里面才能生效。

    :options="{group:{name: 'itxst',pull:'clone'},sort: true}"

    choose:被选中时触发

    unchoose:未选择时触发

    start:开始拖拽时触发

    end:拖拽结束时触发

    add:元素从一个组内拖拽到另一个组内触发

    Update:在组内拖拽更改了顺序触发

    sort:对列表的任何更改调用(添加/更新/删除)

    remove:元素从一个列表中删除到另一个列表

    move:在列表中或在列表之间移动项目的事件

    clone:创建元素克隆时被调用

    change:拖动元素更改位置时被调用

    事件介绍就是上面的了,怎么用也不需要举栗啦。

    就简单介绍一下事件里面事件对象e的内容吧!

    evt.to;    // target list
    evt.from;  // previous list
    evt.oldIndex;  // element's old index within old parent
    evt.newIndex;  // element's new index within new parent
    evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
    evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
    evt.clone // the clone element
    evt.pullMode;  // when item is in another sortable: `"clone"` if cloning, `true` if moving
    

    大篇幅可能懒得看,我简短说一下实现思路:

    1、左边拖拽到右边课程表的时候使用end事件,事件里面的事件对象e可以拿到e.to也就是目标位置的所有信息。

    2、右边的课程表绑定自定义属性用来传递节次信息,key绑定周次信息。

    3、在e.to对象里面,自己细心找一下周次、节次怎么获取。

    4、直接展示拖拽后的内容,用innerHTML把拖拽的元素直接塞里面。

    5、最后肯定是要生成课表的,我们借助二维数组来存放课程信息。第一层为周次,第二层为节次,根据元素内容把数据组合好,最后页面效果有了,课程表的数据也有了。

      <a-card :style="`min-height: ${minHeight}px;`" class="mt50">
        <a-row type="flex" justify="space-between">
          <a-col :md="4" :sm="6" :xs="6" :span="4">
            <a-tabs default-active-key="activetab" tab-position="left" @change="tabChange">
              <a-tab-pane v-for="(item, index) in list" :key="index" :tab="item[0].name">
                <draggable class="dragArea list-group" :list="listDate" :group="{ name: 'people', pull: 'clone', put: false, animation: '300' }" @end="onEnd">
                  <transition-group>
                    <div class="a-row" v-for="element in listDate" :key="element.id">
                      <p>{{ element.name }}</p>
                      <p>{{ element.teacher }}</p>
                    </div>
                  </transition-group>
                </draggable>
              </a-tab-pane>
            </a-tabs></a-col
          <a-col :md="2" :sm="4" :xs="4" :span="2"></a-col>
          <a-col :md="16" :sm="24" :xs="24" :span="16">
            <div class="course">
              <table>
                <thead>
                    <th colspan="2"></th>
                    <th v-for="(val, weekindex) in weeks" :key="weekindex">{{ val }}</th>
                </thead>
                <tbody>
                  <tr v-for="index of 11" :key="index">
                    <td class="week-td" rowspan="4" v-if="index == 1">上午</td>
                    <td class="week-td" rowspan="4" v-if="index == 5">下午</td>
                    <td class="week-td" rowspan="3" v-if="index == 9">晚上</td>
                    <td class="week-td">{{ index }}</td>
                    <draggable group="people" v-for="(val, weekindex) in weeks" :key="weekindex" :dataindex="index" :week="val" tag="td"> </draggable>
                </tbody>
              </table>
            </div>
          </a-col>
        </a-row>
      </a-card>
    

    我vue项目用的是ant design vue组件库,各位看官请挑选自己需要的部分食用吧!

    import draggable from 'vuedraggable';
    export default {
      name: 'custom-clone',
      display: 'Custom Clone',
      order: 3,
      components: {
        draggable,
      data() {
        return {
          minHeight: window.innerHeight - 224,
          list: [
              { name: '语文', id: 1, teacher: '张老师1' },
              { name: '语文', id: 2, teacher: '张老师2' },
              { name: '语文', id: 3, teacher: '张老师3' },
              { name: '语文', id: 4, teacher: '张老师4' },
              { name: '数学', id: 1, teacher: '王老师1' },
              { name: '数学', id: 2, teacher: '王老师2' },
              { name: '数学', id: 3, teacher: '王老师3' },
              { name: '数学', id: 4, teacher: '王老师4' },
              { name: '英语', id: 1, teacher: '李老师1' },
              { name: '英语', id: 2, teacher: '李老师2' },
              { name
    
    
    
    
        
    : '英语', id: 3, teacher: '李老师3' },
              { name: '英语', id: 4, teacher: '李老师4' },
          listDate: [],
          activetab: 0,
          weeks: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
          tableDate: [[], [], [], [], [], [], []],
          weekIndex: '',
          courseIndex: '',
      mounted() {
        this.listDate = this.list[this.activetab];
      methods: {
        onEnd(e) {
          this.weekIndex = e.to.cellIndex;
          this.courseIndex = e.to.__vue__.$vnode.data.attrs.dataindex;
          e.to.innerHTML = e.clone.outerHTML;
          let arr = {
            courseindex: this.courseIndex,
            weekindex: this.weekindex,
            course: e.clone.childNodes[0].innerText,
            teacher: e.clone.childNodes[1].innerText,
          this.$set(this.tableDate[this.weekIndex - 1], this.courseIndex - 1, arr);
        tabChange(key) {
          this.activetab = key;
          this.listDate = this.list[key];
    
    <style lang="less">
    .course {
      height: 700px;
      overflow-y: auto;
      overflow-x: hidden;
      table {
        border: 1px solid #ebebeb;
        margin: 20px auto;
        text-align: center;
        border-collapse: collapse;
      .week-td {
        background-color: #f7f7f7;
      table th {
        border: 1px solid #ebebeb;
        background-color: #f7f7f7;
        padding: 10px;
        width: 100px;
        height: 40px;
        font-size: 14px;
      table td {
        border: 1px solid #ebebeb;
        padding: 4px 10px;
        height: 40px;
        color: #000000;
        font-size: 14px;
    </style>
    

    这里是飞鱼爱吃米,只授渔,不授鱼!

    • 269
  • 私信