最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 基于Vue快速实现列表拖拽排序

    正文概述 掘金(小雄子酱)   2020-12-23   1008

    前言

    在业务中列表拖拽排序是比较常见的需求,常见的JS拖拽库有Sortable.js,Vue.Draggable等,大多数同学遇到这种需求也是更多的求助于这些JS库,其实,使用HTML原生的拖放事件来实现拖拽排序并不复杂,结合Vue的transition-group,还能快速的给排序添加过渡动画。

    基于Vue快速实现列表拖拽排序

    HTML5拖放API

    设置元素为可拖放

    让一个元素能被拖放需要设置 draggable 属性为true(文本、图片和链接的draggable默认就是true)

    <div draggable="true">能被拖放的元素</div>
    

    拖放事件

    拖放涉及到两种元素,一种是被拖拽元素(源对象),一种是放置区元素(目标对象)。如下图所示,按住A元素往B元素拖拽,A元素即为源对象,B元素即为目标对象。

    基于Vue快速实现列表拖拽排序

    不同的对象产生不同的拖放事件。

    触发对象事件名称说明
    源对象dragstart源对象开始被拖动时触发drag源对象被拖动过程中反复触发dragend源对象拖动结束时触发目标对象dragenter源对象开始进入目标对象范围内触发dragover源对象在目标对象范围内移动时触发dragleave源对象离开目标对象范围时触发drop源对象在目标对象范围内被释放时触发

    拖放还有其他一些属性和方法,但对于我们今天要实现的效果,只需要掌握上面提到的这些属性和方法就可以了,如果你想深入探究,可以参考HTML拖放API

    拖拽排序

    下面我们利用拖放API来实现列表的拖拽排序,代码基于Vue实现。

    先不考虑排序动画。代码并不复杂,就全部贴了出来,然后解释一下实现思路:

    1. 由于拖动是实时的,所以没有使用drop而是使用了dragenter触发排序。
    2. 在源对象开始被拖拽时记录其索引dragIndex,当它进入目标对象时(对应dragenter事件),将其插入到目标对象的位置。
    3. 其中dragenter方法中有一个判断this.dragIndex !== index(index为当前目标对象的索引),这是因为源对象同时也是目标对象,当没有这个判断时,源对象开始被拖拽时就会立刻触发自身的dragenter事件,这是不合理的。
    4. dragenter方法里面还有一个判断this.enterIndex !== index是为了避免重复触发目标对象的dragenter事件。

    最终效果如下图所示:

    基于Vue快速实现列表拖拽排序

    <template>
      <ul class="list">
        <li
          @dragenter="dragenter($event, index)"
          @dragover="dragover($event, index)"
          @dragstart="dragstart(index)"
          draggable
          v-for="(item, index) in list"
          :key="item.label"
          class="list-item"
         >
          {{item.label}}
        </li>
      </ul>
    </template>
    <script>
    export default {
      data() {
        return {
          list: [
            { label: '列表1' },
            { label: '列表2' },
            { label: '列表3' },
            { label: '列表4' },
            { label: '列表5' },
            { label: '列表6' },
          ],
          dragIndex: '',
          enterIndex: '',
        };
      },
      methods: {
        dragstart(index) {
          this.dragIndex = index;
        },
        dragenter(e, index) {
          e.preventDefault();
          // 避免源对象触发自身的dragenter事件
          if (this.dragIndex !== index) {
            // 避免重复触发目标对象的dragenter事件
            if (this.enterIndex !== index) {
              const source = this.list[this.dragIndex];
              this.list.splice(this.dragIndex, 1);
              this.list.splice(index, 0, source);
              // 排序变化后目标对象的索引变成源对象的索引
              this.dragIndex = index;
            } else {
              this.enterIndex = index;
            }
          }
        },
        dragover(e, index) {
          e.preventDefault();
        },
      },
    };
    </script>
    <style lang="scss" scoped>
    .list {
      list-style: none;
      .list-item {
        cursor: move;
        width: 300px;
        background: #EA6E59;
        border-radius: 4px;
        color: #FFF;
        margin-bottom: 6px;
        height: 50px;
        line-height: 50px;
        text-align: center;
      }
    }
    </style>
    

    减去HTML和CSS,核心的dragenter只有不超过15行的代码,就可实现一个拖拽排序功能。当然这个拖拽效果有点生硬,下面使用Vue自带的transition-group组件,给排序添加平滑的过渡效果。

    排序动画

    如果不熟悉Vue的transition-group,请先学习Vue的列表的排序过渡,这里不再赘述。

    为了便于和上面的代码进行比较,同样一次性把全部代码贴出,可以看到代码变动并不大,只需把HTML的ul元素改为transition-group,在methods中新增shuffle方法,在CSS中新增一个过渡transition: transform .3s;即可实现开头第一张图所展示的拖拽排序效果了。

    你可以点击此链接进行在线体验。

    <template>
      <div>
        <transition-group
          name="drag"
          class="list"
          tag="ul"
        >
          <li
            @dragenter="dragenter($event, index)"
            @dragover="dragover($event, index)"
            @dragstart="dragstart(index)"
            draggable
            v-for="(item, index) in list"
            :key="item.label"
            class="list-item">
            {{item.label}}
          </li>
        </transition-group>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          list: [
            { label: '列表1' },
            { label: '列表2' },
            { label: '列表3' },
            { label: '列表4' },
            { label: '列表5' },
            { label: '列表6' },
          ],
          dragIndex: '',
          enterIndex: '',
        };
      },
      methods: {
        shuffle() {
          this.list = this.$shuffle(this.list);
        },
        dragstart(index) {
          this.dragIndex = index;
        },
        dragenter(e, index) {
          e.preventDefault();
          // 避免源对象触发自身的dragenter事件
          if (this.dragIndex !== index) {
            // 避免重复触发目标对象的dragenter事件
            if (this.enterIndex !== index) {
              const moving = this.list[this.dragIndex];
              this.list.splice(this.dragIndex, 1);
              this.list.splice(index, 0, moving);
              // 排序变化后目标对象的索引变成源对象的索引
              this.dragIndex = index;
            } else {
              this.enterIndex = index;
            }
          }
        },
        dragover(e, index) {
          e.preventDefault();
        },
      },
    };
    </script>
    <style lang="scss" scoped>
    .list {
      list-style: none;
      .drag-move {
        transition: transform .3s;
      }
      .list-item {
        cursor: move;
        width: 300px;
        background: #EA6E59;
        border-radius: 4px;
        color: #FFF;
        margin-bottom: 6px;
        height: 50px;
        line-height: 50px;
        text-align: center;
      }
    }
    </style>
    

    如果想使用原生JS实现列表的拖拽排序和过渡动画,可以参考这篇文章:js drag拖动排序


    起源地下载网 » 基于Vue快速实现列表拖拽排序

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元