vue實現拖拽排序


基於vue實現列表拖拽排序的效果

在日常開發中,特別是管理端,經常會遇到要實現拖拽排序的效果;這里提供一種簡單的實現方案。


首先,我們先了解一下js原生拖動事件:

在拖動目標上觸發事件 (源元素):

  • ondragstart - 用戶開始拖動元素時觸發
  • ondrag - 元素正在拖動時觸發
  • ondragend - 用戶完成元素拖動后觸發

釋放目標時觸發的事件:

  • ondragenter - 當被鼠標拖動的對象進入其容器范圍內時觸發此事件
  • ondragover - 當某被拖動的對象在另一對象容器范圍內拖動時觸發此事件
  • ondragleave - 當被鼠標拖動的對象離開其容器范圍內時觸發此事件
  • ondrop - 在一個拖動過程中,釋放鼠標鍵時觸發此事件

    基於js的原生拖拽事件,本次實現的拖拽排序的原理大概是:鼠標按住列表某一項開始拖動時觸發ondragstart事件,將該拖動項用變量記錄下來;接着拖拽過程中,該拖動項經過列表其他項時,觸發ondragenter事件,同樣記錄該拖動項最后經過的列表其他項的數據,最后在ondragend 事件中將數組列表刪掉一開始ondragstart事件記錄的拖動項,並將刪掉的數據插入ondragenter事件最后記錄的位置,完成拖動排序。


具體代碼如下:

<template>
    <div class="test_wrapper" @dragover="dragover($event)">
        <transition-group class="transition-wrapper" name="sort">
            <div v-for="(item) in dataList" :key='item.id' class="sort-item"
                :draggable="true"
                @dragstart="dragstart(item)"
                @dragenter="dragenter(item,$event)"
                @dragend="dragend(item,$event)"
                @dragover="dragover($event)"
            >
                {{ item.label }}
            </div>
        </transition-group>
    </div>
</template>

<script lang="ts">
    import {Vue, Component, Prop, Watch} from "vue-property-decorator";
    import { addWebsite } from '@/api'
    @Component({
        components: {}
    })
    export default class Test extends Vue {

        oldData: any = null; // 開始排序時按住的舊數據
        newData: any = null; // 拖拽過程的數據

        // 列表數據
        dataList:any = [
            { id:1,label:'測試一號' },
            { id:2,label:'測試二號' },
            { id:3,label:'測試三號' },
            { id:4,label:'測試四號' },
        ];

        dragstart(value: any) {
            this.oldData = value
        }

        // 記錄移動過程中信息
        dragenter(value: any, e: any) {
            this.newData = value
            e.preventDefault()
        }

        // 拖拽最終操作
        dragend(value: any, e: any) {
            if (this.oldData !== this.newData) {
                let oldIndex = this.dataList.indexOf(this.oldData)
                let newIndex = this.dataList.indexOf(this.newData)
                let newItems = [...this.dataList]
                // 刪除老的節點
                newItems.splice(oldIndex, 1)
                // 在列表中目標位置增加新的節點
                newItems.splice(newIndex, 0, this.oldData)
                this.dataList = [...newItems]
            }
        }


        // 拖動事件(主要是為了拖動時鼠標光標不變為禁止)
        dragover(e: any) {
            e.preventDefault()
        }


    };
</script>

另外

為了實現拖動的動畫效果,這里用到了transition-group組件,如上面代碼顯示,將transition-group組件的屬性name設為‘sort’;並添加以下代碼;

        .sort-move {
            transition: transform 0.3s;
        }

注意:為了讓transition有效果出現,v-for渲染的數據列表必須有key屬性,且該key屬性不可設為index;


最終效果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM