【JavaScript】拖拽实现,列表互相拖拽,时间轴拖拽,原生draggable实现

原生draggable实现拖拽列表


在这里插入图片描述

一个原生实现的多列表拖拽,和拖拽排序。
类似视频编辑器的时间轴拖拽,资源拖拽。
效果如视频,代码如下。
index.vue

<template>
    <p>文件列表</p>
    <div class="file-list">

        <div class="file" v-for="(file,index) in fileList"
             draggable="true"
             @dragstart="fileDragStart($event,file)"
             @dragend="fileDragEnd($event,file)"
             :key="'file'+index">
            {
   
   { file.name }}
        </div>
    </div>
    <div>时间轴{
   
   { moveIn }}</div>
    <div class="line-list" :class="{'line-in':lineIn}"
         @dragenter="lineDragEnter"
         @dragleave="lineDragLeave"
         @dragover="lineDragOver"
         @drop="lineDropFile">
        <transition-group name="list">
            <div class="line" v-for="(line,index) in lineList"
                 :key="'line'+line.key"
                 :style="style(line)"
                 :title="line.name"
                 @dragstart="lineDragStart($event,index)"
                 @dragend="lineDragEnd"
                 draggable="true"
                 @dragenter="lineItemDragEnter($event,index)"
                 @dragleave="lineItemDragLeave"
                 @drop.stop="lineItemDropFile(index)"
            >
                {
   
   { line.name }}
            </div>
        </transition-group>
    </div>
  <!--    隐藏对象-->
    <div class="hidden">
        <div id="move" ref="moveBlock">
            {
   
   { nowFile.name }}
        </div>
    </div>
</template>

<script setup>
import { randColor } from '@/utils/color.js' // 随机生成颜色
import { uuid } from '@/utils/key.js'// 生成唯一值
import { ref } from 'vue'
const fileList = ref( [
    { name: '视频1.mp4' , type: 'video' , duration: 10 } ,
    { name: '音频2.mp4' , type: 'audio' , duration: 60 } ,
    { name: '视频3.mp4' , type: 'video' , duration: 70 } ,
    { name: '音频4.mp4' , type: 'audio' , duration: 80 } ,
] )
const lineList = ref( [] )
const moveBlock = ref( null )
const nowFile = ref( { name: '' } )
const lineIn = ref( false )
let dragType = 'create'
let moveIndex = ''
let moveIn = ''
const style = ( file ) => {
    return {
        background: file.color ,
        width: file.duration * 5 + 'px'
    }
}

/**
 * 文件列表拖拽开始
 * @param $event
 * @param file
 */
const fileDragStart = ( $event , file ) => {
    console.log( '文件列表拖拽开始' , $event , file )
    dragType = 'create'
    nowFile.value = file
    let width = nowFile.value.duration * 2
    moveBlock.value.style.width = (width > 270 ? 270 : width) + 'px'
    $event.dataTransfer.setDragImage( moveBlock.value , 0 , 0 )
}

/**
 * 文件列表拖拽结束
 * @param $event
 * @param file
 */
const fileDragEnd = ( $event , file ) => {
    console.log( '文件列表拖拽结束' , $event , file )
    lineIn.value = false
}


/**
 * 时间轴进入
 * @param $event
 * @constructor
 */
const lineDragEnter = ( $event ) => {
    console.log( '时间列表进入' , $event )
    $event.preventDefault(); //阻止默认事件
    lineIn.value = true
}
/**
 * 时间轴离开
 * @param $event
 * @param file
 * @constructor
 */
const lineDragLeave = ( $event , file ) => {
    console.log( '时间列表离开' , $event )
    $event.preventDefault(); //阻止默认事件
    lineIn.value = false
}

/**
 * 时间轴阻止默认
 * @param $event
 * @constructor
 */
const lineDragOver = ( $event ) => {
    $event.preventDefault(); //阻止默认事件
}

/**
 * 时间轴放入
 * @param $event
 */
const lineDropFile = ( $event ) => {
    console.log( '时间列表放入' ,dragType, $event )
    // 放在空的地方
    if ( dragType === 'create' ) {
        let color = randColor()
        let file = {
            key: uuid() ,
            name: nowFile.value.name ,
            type: nowFile.value.type ,
            duration: nowFile.value.duration ,
            color: color
        }
        console.log( 'file' , file )
        lineList.value.push( file )
    }
}

/**
 * 时间轴拖动开始
 * @param $event
 * @constructor
 */
const lineDragStart = ( $event , index ) => {
    console.log( '时间轴拖动开始' , $event )
    dragType = 'move'
    moveIndex = index
}
/**
 * 时间轴拖动结束
 * @param $event
 * @constructor
 */
const lineDragEnd = ( $event ) => {
    console.log( '时间轴拖动结束' , $event )
    moveIndex = ''
}


/**
 * 时间轴内容进入
 * @param $event
 * @constructor
 */
const lineItemDragEnter = ( $event,index ) => {
    console.log( '时间轴进入' , $event )
    $event.preventDefault(); //阻止默认事件
    moveIn = index
}
/**
 * 时间轴内容离开
 * @param $event
 * @constructor
 */
const lineItemDragLeave = ( $event  ) => {
    console.log( '时间轴离开' , $event )
    $event.preventDefault(); //阻止默认事件
    moveIn = ''
}

/**
 * 时间轴放入
 * @param index
 */
const lineItemDropFile = ( index ) => {
    console.log( '时间轴放入' , index )
    // 放在某个轴上
    if ( dragType === 'create' ) {
        let color = randColor()
        let file = {
            key: uuid() ,
            name: nowFile.value.name ,
            type: nowFile.value.type ,
            duration: nowFile.value.duration ,
            color: color
        }
        console.log( 'file' , file )
        lineList.value.splice(index,0,file)
    }
    // 移动
    if ( dragType === 'move' ) {
        console.log( '移动' ,moveIndex,index)
        let list = lineList.value
        if(moveIndex > index){
            const item = lineList.value[moveIndex]
            list.splice(moveIndex,1)
            list.splice(index,0,item)
        }else{
            const item = lineList.value[moveIndex]
            console.log('移动',item,list)
            list.splice(moveIndex,1)
            list.splice(index,0,item)
            console.log("移动到后面",list)
        }
        lineList.value = list
    }
}
</script>

<style lang="less" scoped>
.hidden {
  position: fixed;
  left: 0;
  top: -100px;

  #move {
    min-width: 20px;
    height: 20px;
    background: red;
    border: 1px solid #07b3c9;
    overflow: hidden;
  }
}


.line-list {
  height: 200px;
  overflow-y: auto;

  .line {
    user-select: none;
    overflow: hidden;
    height: 20px;
    white-space: nowrap; /*不显示的地方用省略号...代替*/
    text-overflow: ellipsis; /* 支持 IE */
  }
}

.line-in {
  background: #999;
}

.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
    transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
    opacity: 0;
    transform: translateX(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
    position: absolute;
}
</style>

猜你喜欢

转载自blog.csdn.net/sky529063865/article/details/129871505
今日推荐