Vue实现的可拖拽排序组件-完美提升用户体验

一、组件介绍

Vue是一个优秀的前端框架,能够帮助开发者快速构建优秀的Web应用程序。其中,拖拽排序组件是一种非常实用的UI组件,能够帮助用户进行元素的拖拽、移动等操作,提高用户的使用效率。

本文介绍的这个组件使用Vue框架实现,使用简单,且支持多种常见的拖拽排序功能,包括拖拽移动、交换位置、拖拽排序、拖拽删除等,非常适用于需要拖拽排序的场合,包括网页排版、图片库管理等领域。

二、组件应用

下面是一个使用Vue实现的可拖拽排序组件的例子,供读者参考使用:

  <template>
    <ul class="drag-list">
      <li
        v-for="(item, index) in list"
        :key="index"
        :class="{ active: activeIndex === index }"
        @mousedown="handleMousedown(index, $event)"
        @mousemove="handleMousemove(index, $event)"
        @mouseup="handleMouseup(index)"
        :style="getStyle(index)"
      >
        {{ item }}
        <i class="delete" @click="handleDelete(index)"></i>
      </li>
    </ul>
  </template>

  <script>
  export default {
    data() {
      return {
        list: ["元素1", "元素2", "元素3", "元素4", "元素5", "元素6", "元素7"],
        activeIndex: -1,
        dragStartPos: { x: 0, y: 0 },
        draggingPos: { x: 0, y: 0 },
        distanceX: 0,
        distanceY: 0,
        dragging: false
      };
    },
    methods: {
      handleMousedown(index, e) {
        this.activeIndex = index;

        this.dragging = true;
        this.dragStartPos.x = e.pageX;
        this.dragStartPos.y = e.pageY;

        this.draggingPos.x = e.pageX;
        this.draggingPos.y = e.pageY;
      },
      handleMousemove(index, e) {
        if (this.dragging) {
          this.distanceX = e.pageX - this.draggingPos.x;
          this.distanceY = e.pageY - this.draggingPos.y;

          this.draggingPos.x = e.pageX;
          this.draggingPos.y = e.pageY;

          const targetIndex = this.getTargetIndex(index, e);

          if (targetIndex !== index) {
            this.list.splice(targetIndex, 0, this.list.splice(index, 1)[0]);
            this.activeIndex = targetIndex;
          }

          // 限制拖动范围
          const limitList = document.querySelector(".drag-list");
          const limitTop = limitList.offsetTop;
          const limitBottom = limitList.offsetHeight + limitTop;

          if (e.pageY  limitBottom) {
            window.scrollTo(0, window.pageYOffset + 10);
          }
        }
      },
      handleMouseup(index) {
        if (this.dragging) {
          this.dragging = false;

          if (this.distanceX !== 0 || this.distanceY !== 0) {
            this.list.splice(this.activeIndex, 1);
            this.list.splice(index, 0, this.list[this.activeIndex]);
          }

          this.activeIndex = -1;
          this.distanceX = 0;
          this.distanceY = 0;
        }
      },
      handleDelete(index) {
        this.list.splice(index, 1);
      },
      getStyle(index) {
        if (this.dragging && this.activeIndex === index) {
          return {
            transform: `translate(${this.distanceX}px, ${this.distanceY}px)`,
            zIndex: 99
          };
        }
      },
      getTargetIndex(index, e) {
        const targetEle = document.elementFromPoint(
          e.clientX - this.distanceX,
          e.clientY - this.distanceY
        );
        if (targetEle.classList.contains("delete")) {
          return index;
        } else {
          const targetList = targetEle.parentNode;
          const targetIndex = Array.prototype.indexOf.call(
            targetList.children,
            targetEle
          );
          return targetIndex;
        }
      }
    }
  };
  </script>

  <style>
  .drag-list {
    list-style-type: none;
    padding: 0;
    margin: 0;
    border: 1px solid #ccc;
  }

  .drag-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px;
    border-top: 1px solid #eee;
  }

  .drag-list li:hover {
    background-color: #f0f0f0;
  }

  .drag-list .active {
    background-color: #aad8d3;
    color: #fff;
  }

  .drag-list i {
    color: red;
    cursor: pointer;
  }
  </style>

这是一个简单而功能强大的可拖拽排序组件,解释代码如下:

  • 在data中定义list,用来存储排序列表数据
  • 该组件提供四个事件回调函数:handleMousedown、handleMousemove、handleMouseup、handleDelete。handleMousedown事件绑定到列表元素上,当用户鼠标按下时会触发该事件;handleMousemove事件绑定到列表元素上,当用户拖动元素时会多次触发该事件;handleMouseup事件绑定到列表元素上,当用户松开鼠标时会触发该事件;handleDelete事件绑定到每个元素的删除按钮。组件内部通过判断拖拽距离是否为0,来判断是否需要进行元素的排序。
  • getStyle函数用来设置被拖拽元素的样式
  • getTargetIndex函数用来获取列表位置

三、组件优化方案

虽然上面的组件已经实现拖拽排序的功能,但是在特定情况下,该组件还有较大的优化空间,可以提高程序的性能和用户体验。以下是优化方案:

1、使用window.requestAnimationFrame()

使用requestAnimationFrame()方法代替mousemove()事件,可以在不阻塞浏览器的情况下,让组件流畅地运行。

  handleMousemove(index, e) {
    if (this.dragging) {
      window.requestAnimationFrame(() => {
        // 处理拖拽元素的位置变化等逻辑
      })
    }
  }

2、使用位运算优化性能

在复杂的拖拽操作中,位运算可以帮助提升一些性能,比如位移运算、按位与运算等。

  handleMousemove(index, e) {
    if (this.dragging) {
      window.requestAnimationFrame(() => {
        const deltaX = e.pageX - this.draggingPos.x;
        const deltaY = e.pageY - this.draggingPos.y;
        const targetIndex =
          (Math.round(e.pageY / this.$refs.itemHeight) - 1) * this.cols +
          Math.round(e.pageX / this.$refs.itemWidth) -
          1;
        // 处理拖拽元素的位置变化等逻辑
      })
    }
  }

3、使用CSS3动画和transition

在标准的页面布局中,大量使用JS来实现可视化效果,这种实现方式会造成过多的DOM操作和样式请求,导致页面重新渲染。如果我们使用CSS3动画和transition,我们就可以在不占用js的情况下,通过GPU加速来快速渲染页面。

  .drag-list li {
    transition: transform .2s ease-out;
  }

4、使用虚拟列表

在长列表中,可能存在大量的DOM节点渲染,这一过程可能比较耗时,影响用户体验。使用虚拟列表方案,可以只渲染列表中可视化的部分,避免过多的DOM操作。

  <template>
    <div class="drag-list">
      <div :style="{ height: itemHeight * rowCount + 'px' }"></div>
      <div
        ref="listWrapper"
        :style="{ height: wrapperHeight }"
        @scroll="onScroll"
      >
        <ul :style="{ transform: 'translateY(' + scrollTop + 'px)' }">
          <li
            v-for="(item, index) in visibleList"
            :key="item.id"
            :style="{ top: (index % cols) * itemHeight + 'px', left: Math.floor(index / cols) * itemWidth + 'px' }"
            @mousedown="handleMousedown(index, $event)"
            @mouseup="handleMouseup(index)"
          >
            {{ item.value }}
          </li>
        </ul>
      </div>
    </div>
  </template>

  <script>
  export default {
    computed: {
      visibleList() {
        const start = Math.floor(this.scrollTop / this.itemHeight) * this.cols;
        const end = start + (this.rowCount + 1) * this.cols;
        return this.dataList.slice(start, end);
      }
    },
    methods: {
      onScroll() {
        this.scrollTop = this.$refs.listWrapper.scrollTop;
      }
    }
  };
  </script>
  <style>
    .drag-list {
      position: relative;
    }

    .drag-list ul {
      position: absolute;
      list-style: none;
      padding: 0;
      margin: 0;
      width: 100%;
    }

    .drag-list li {
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 100px;
      height: 100px;
      border: 1px solid #ddd;
      box-sizing: border-box;
    }

    .drag-list li:hover {
      background: #f8f8f8;
    }
  </style>

四、总结

本文介绍了使用Vue框架实现的可拖拽排序组件,并提供了一些常见的优化方案,可以帮助开发者提高程序的性能和用户体验。在实际应用中,我们还可以根据具体情况进行进一步的优化,让程序更加符合用户需求。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/311406.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2025-01-05 13:23
下一篇 2025-01-05 13:23

相关推荐

  • KeyDB Java:完美的分布式高速缓存方案

    本文将从以下几个方面对KeyDB Java进行详细阐述:KeyDB Java的特点、安装和配置、使用示例、性能测试。 一、KeyDB Java的特点 KeyDB Java是KeyD…

    编程 2025-04-29
  • 如何修改ant组件的动效为中心

    当我们使用Ant Design时,其默认的组件动效可能不一定符合我们的需求,这时我们需要修改Ant Design组件动效,使其更加符合我们的UI设计。本文将从多个方面详细阐述如何修…

    编程 2025-04-29
  • Ant Design组件的动效

    Ant Design是一个基于React技术栈的UI组件库,其中动效是该组件库中的一个重要特性之一。动效的使用可以让用户更清晰、更直观地了解到UI交互的状态变化,从而提高用户的满意…

    编程 2025-04-29
  • Python中接收用户的输入

    Python中接收用户的输入是一个常见的任务,可以通过多种方式来实现。本文将从以下几个方面对Python中接收用户的输入做详细阐述。 一、使用input函数接收用户输入 Pytho…

    编程 2025-04-29
  • Python弹框让用户输入

    本文将从多个方面对Python弹框让用户输入进行阐述,并给出相应的代码示例。 一、Tkinter弹窗 Tkinter是Python自带的图形用户界面(GUI)库,通过它可以创建各种…

    编程 2025-04-28
  • Unity运行模式下Scene视图无法拖拽的解决方法

    解决Unity在运行模式下,无法使用鼠标拖拽Scene视图的问题,有以下几个方法。 一、场景模式和运行模式的区别 首先我们需要了解场景模式和运行模式的区别。 场景模式下,我们可以自…

    编程 2025-04-28
  • Zookeeper ACL 用户 anyone 全面解析

    本文将从以下几个方面对Zookeeper ACL中的用户anyone进行全面的解析,并为读者提供相关的示例代码。 一、anyone 的作用是什么? 在Zookeeper中,anyo…

    编程 2025-04-28
  • Python中获取用户输入命令的方法解析

    本文将从多个角度,分别介绍Python中获取用户输入命令的方法,希望能够对初学者有所帮助。 一、使用input()函数获取用户输入命令 input()是Python中用于获取用户输…

    编程 2025-04-27
  • Python接收用户键盘输入用法介绍

    本文将从多个方面对Python接收用户键盘输入进行详细阐述,给出相关的代码示例,让大家更好的了解和应用Python的输入功能。 一、输入函数 在Python中,我们可以使用两种函数…

    编程 2025-04-27
  • 如何在Linux中添加用户并修改配置文件

    本文将从多个方面详细介绍在Linux系统下如何添加新用户并修改配置文件 一、添加新用户 在Linux系统下创建新用户非常简单,只需使用adduser命令即可。使用以下命令添加新用户…

    编程 2025-04-27

发表回复

登录后才能评论