vue实现拖拽排序效果

本文实例为大家分享了vue实现拖拽排序效果的具体代码,供大家参考,具体内容如下

效果预览

组件 drag.vue

<template>
  <TransitionGroup name="group-list" tag="ul">
    <li
      v-for="(item, index) in list"
      :key="item.name"
      :draggable="item.draggable"
      :class="[
        'list-item',
        {
          'is-dragover':
            index === dropIndex && item.draggable && config.exchange,
        },
      ]"
      @dragstart="onDragstart($event, index)"
      @dragenter="onDragenter(index)"
      @dragover.prevent="onDragover(index)"
      @dragleave="onDragleave"
      @dragend="onDragend"
      @drop="onDrop"
    >
      <slot :item="item" />
    </li>
  </TransitionGroup>
</template>

<script>
export default {
  name: "Draggable",
  props: {
    list: {
      type: Array,
      default: () => [],
    },
    config: {
      type: Object,
      default: () => ({
        name: "",
        push: true,
        pull: true,
        exchange: true,
      }),
    },
  },

  data() {
    return {
      dragIndex: null,
      dropIndex: null,
    };
  },

  computed: {
    isPush() {
      const { dropIndex, dragIndex } = this;
      return dropIndex !== null && dragIndex === null;
    },

    isExchange() {
      const { dropIndex, dragIndex } = this;
      return dragIndex !== null && dropIndex !== null;
    },

    pushCbName() {
      const {
        config: { name },
      } = this;
      return `${name}-push-callback`;
    },
  },

  methods: {
    onDragstart(e, i) {
      const {
        list,
        config: { name },
        transferData,
      } = this;

      this.dragIndex = i;

      if (name) {
        transferData({ e, key: name, type: "set", data: list[i] });
      } else {
        throw new Error("缺少配置关联名name");
      }

      this.$emit("drag-start", i);
    },

    onDragenter(i) {
      this.dropIndex = i;
      this.$emit("drag-enter", i);
    },

    onDragover(i) {
      const { dragIndex, dropIndex } = this;
      if (i === dragIndex || i === dropIndex) return;
      this.dropIndex = i;
      this.$emit("drag-over", i);
    },

    onDragleave() {
      this.dropIndex = null;
    },

    onDrop(e) {
      const {
        list,
        dropIndex,
        dragIndex,
        config: { name, push: enablePush, exchange },
        isPush,
        isExchange,
        pushCbName,
        storage,
        resetIndex,
        transferData,
      } = this;

      if (dropIndex === dragIndex || !exchange) return;

      if (isPush) {
        if (!enablePush) {
          resetIndex();
          return;
        }

        if (name) {
          list.splice(
            dropIndex,
            0,
            transferData({ e, key: name, type: "get" })
          );

          storage("set", pushCbName, true);
        } else {
          resetIndex();
          throw new Error("缺少配置关联属性name");
        }
        resetIndex();
        return;
      }

      if (isExchange) {
        const drapItem = list[dragIndex];
        const dropItem = list[dropIndex];
        list.splice(dropIndex, 1, drapItem);
        list.splice(dragIndex, 1, dropItem);
      }

      resetIndex();
    },

    onDragend() {
      const {
        list,
        dragIndex,
        config: { pull: enablePull },
        pushCbName,
        storage,
        resetIndex,
      } = this;

      if (enablePull) {
        const isPushSuccess = storage("get", pushCbName);

        if (isPushSuccess) {
          list.splice(dragIndex, 1);
          storage("remove", pushCbName);
        }
      }
      resetIndex();
      this.$emit("drag-end");
    },

    storage(type, key, value) {
      return {
        get() {
          return JSON.parse(localStorage.getItem(key));
        },
        set() {
          localStorage.setItem(key, JSON.stringify(value));
        },
        remove() {
          localStorage.removeItem(key);
        },
      }[type]();
    },

    resetIndex() {
      this.dropIndex = null;
      this.dragIndex = null;
    },

    transferData({ e, key, type, data } = {}) {
      if (type === "get") {
        return JSON.parse(e.dataTransfer.getData(`${key}-drag-key`));
      }

      if (type === "set") {
        e.dataTransfer.setData(`${key}-drag-key`, JSON.stringify(data));
      }
    },
  },
};
</script>

<style  scoped>
.list-item {
  list-style: none;
  position: relative;
  margin-bottom: 10px;
  border-radius: 4px;
  padding: 4px;
  background-color: #fff;
  cursor: move;
}

.list-item.is-dragover::before {
  content: "";
  position: absolute;
  bottom: -4px;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #0c6bc9;
}

.list-item.is-dragover::after {
  content: "";
  position: absolute;
  bottom: -8px;
  left: -6px;
  border: 3px solid #0c6bc9;
  border-radius: 50%;
  width: 6px;
  height: 6px;
  background-color: #fff;
}

.group-list-move {
  transition: transform 0.8s;
}
</style>

使用范例

index.vue

<template>
  <div class="dragBox">
    <Drag style="width: 200px" :list="list1" :config="config1">
      <template v-slot="{ item }">
        <div class="item">
          {{ item.name }}
        </div>
      </template>
    </Drag>

    <Drag style="width: 200px" :list="list2" :config="config2">
      <template v-slot="{ item }">
        <div class="item">
          {{ item.name }}
        </div>
      </template>
    </Drag>
  </div>
</template>

<script>
import Drag from "./drag.vue";

export default {
  components: {
    Drag,
  },

  data() {
    return {
      list1: new Array(10).fill(0).map((_, i) => ({
        name: `列表1 - ${i + 1}`,
        draggable: true,
      })),

      config1: {
        name: "test",
        push: true,
        pull: true,
        exchange: true,
      },

      list2: new Array(10).fill(0).map((_, i) => ({
        name: `列表2 - ${i + 1}`,
        draggable: true,
      })),

      config2: {
        name: "test",
        push: true,
        pull: true,
        exchange: true,
      },
    };
  },
};
</script>

<style  scoped>
.dragBox {
  display: flex;
  justify-content: center;
}
.item {
  border: 1px solid #ccc;
  width: 200px;
  height: 30px;
  text-align: center;
}
</style>

参数说明

list: 渲染列表
config: {
    name: '', // 跨列表关联名,跨列表拖拽时必传
    push: true, // 当前列表是否支持从其他列表push元素进来
    pull: true, // 将当前列表的某个元素拖拽并添加到其他列表里,该元素是否从当前列表移除
    exchange: true, // 当前列表元素之间是否支持交换位置
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • vue拖拽排序插件vuedraggable使用方法详解

    大家好,最近做的项目要用到拖拽排序,我现在的项目是vue项目,所以我就屁颠屁颠的去百度有木有这样功能的插件,我就知道一定会有,那就是vuedraggable,这是一款很棒的拖拽插件,下面我来说一下怎么引入 首先在vue项目中,用npm包下载下来 npm install vuedraggable -S 下载下来后,引入插件,在你的vue文件的script标签里面这样引入 import draggable from 'vuedraggable' 别忘了下面要注册组件 components: { dr

  • vuedraggable+element ui实现页面控件拖拽排序效果

    项目要实现一些控件的拖拽排序.从而找到了这款vuedraggable控件,供大家参考,具体内容如下 如上图要实现这些控件的拖拽排序 这是拖拽后 由于公司网络的原因,项目没有使用npm,都是使用的引入的js <script type="text/javascript" src="lib/sortable/Sortable.min.js"></script> <script type="text/javascript"

  • antdesign-vue结合sortablejs实现两个table相互拖拽排序功能

    实现效果 本来想在网上看看有没有基于antdesign做的,然后发现是真的少啊!废话不多说,先上图: sortablejs介绍 首先先来认识一下这个插件: sortablejs 大家可以去细读一下它的api文档: 这边我就着重介绍一下我用到的api. 1.group可以传入对象,参数值为name,pull,put, name:如果是要两个列表下进行拖动的话,name的值必须为一样: pull:pull用来定义从这个列表容器移动出去的设置,true/false/'clone'/function t

  • vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序

    vue拖拽克隆clone组件API, vue.draggable实现盒子之间相互拖拽排序克隆(网上资源整理的文档) 效果图: -------------------------------------------------------------------------------- 首先需要安装vuedraggable依赖包: npm install vuedraggable --save 因为拖拽组件依赖sortablejs ,如果项目没有安装sortablejs ,可能需要安装一下 np

  • Vue 基于 vuedraggable 实现选中、拖拽、排序效果

    今天有个朋友说要做个效果:Vue实现拖拽排序,要有 checked,输出结果是排序后的,要全选,未选中的不能拖动. 其实我之前基于 Sortable 做过一个类似的效果.也给他看过了,没看太明白,他就自己基于 vuedraggable 实现了一下. 正好有点问题给他解决了一下.废话不多说,先上最终效果:Vue 拖拽排序效果 测试地址.下面就是最终效果图. 效果一:实现选中 和 全选效果 就下面这样,elementUI 官方 Demo.很简单毫无挑战呀. <el-checkbox :indeter

  • vue 使用 sortable 实现 el-table 拖拽排序功能

    本文给大家介绍vue 使用 sortable 实现 el-table 拖拽排序功能,具体内容如下所示: npm 下载: npm install sortablejs --save 引入: import Sortable from "sortablejs"; 代码: <template> <div class="table"> <el-table ref="dragTable" :data="tableDat

  • 利用Vue-draggable组件实现Vue项目中表格内容的拖拽排序

    Vue-draggable 的github传送门 : https://github.com/SortableJS/Vue.Draggable 一. 下载依赖包:npm install vuedraggable -S  二. 在需要使用的当前界面引入依赖,注册组件: import draggable from "vuedraggable"; export default { components: { draggable, } 三. 在template 中建立表格,分别写出thead 部

  • vue.draggable实现表格拖拽排序效果

    本文实例为大家分享了vue.draggable实现表格拖拽排序效果展示的具体代码,供大家参考,具体内容如下 主要使用vuedraggable和sortablejs两个组件. 1.安装组件 npm install vuedraggable npm install sortablejs 2.引入组件 import draggable from 'vuedraggable'; import Sortable from 'sortablejs'; export default { components:

  • 基于Vue实现平滑过渡的拖拽排序功能

    最近重读Vue官方文档,在 列表的排序过渡 这一小节,文档提到,<transition-group> 组件有一个特殊的地方,不仅可以实现进入和离开动画,还可以改变定位,官网示例如下: 例子中实现的效果看起来还是非常不错的,这个效果使我想起来另外一个使用场景,之前我在实现一个列表展示需求的时候,PM想让这个列表具有拖动排序的功能,方便他操作(事实上我最后并没有给他做哈哈),拖动的动画跟这个很像,网上搜索一下,类似插件应该很多,那如果我们自己来实现一个,问题在哪里呢? 首先要拖拽元素,记录元素拖拽

  • vue实现列表拖拽排序的功能

    在日常开发中,特别是管理端,经常会遇到要实现拖拽排序的效果:这里提供一种简单的实现方案. 此例子基于vuecli3 首先,我们先了解一下js原生拖动事件: 在拖动目标上触发事件 (源元素): ondragstart - 用户开始拖动元素时触发 ondrag - 元素正在拖动时触发 ondragend - 用户完成元素拖动后触发 释放目标时触发的事件: ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件 ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触

随机推荐