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/zh-tw/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

發表回復

登錄後才能評論