vue实现前端拖拽div位置交换的方法详解

 更新时间:2025年01月04日 11:56:50   作者:Loong_DQX  
这篇文章主要介绍了如何使用Vue技术实现一个简单的备忘录应用,包括添加条目和拖拽条目两个功能,文章还详细解释了如何使用Vue的draggable属性和JavaScript获取同级元素节点的方法,需要的朋友可以参考下

一、场景描述

类似备忘录,点击添加按钮,多一条条目。然后手动拖拽条目可以更换条目之前的位置。

二、问题拆解

这里可以分成两个问题,第一个是添加,第二个是拖拽。
添加的实现:vue技术像一个前端页面的数据管理器,它里面的 “v-for”列表渲染指令支持当列表数据增加的时候实现重新渲染增加一个条目。
拖拽的实现:拖拽事件,开始的时候需要记录所拖拽的目标,拖拽经过的实现交换。

三、知识背景

3.1 vue拖拽事件

在这里,我们使用的是开始拖拽事件和在有效区域移动事件,为的是得到所拖拽的标签元素以及被拖动标签元素所要到达的原有标签元素的位置。
下面举例一下拖拽事件怎么用。

首先需要开始标签拖拽功能:draggable=“true” ,再添加拖拽事件。

<div class="task" draggable="true" @dragstart.self = "ondragstart($event)" @dragover.self = "ondragover($event)">
</div>

3.2 js获得同级元素节点

ele.previousSibling ele.previousElementSibling 获取同级的上下级,(前一个标签元素和后一个标签元素)
ele.nextSibling ele.nextElementSibling

<input id="a5" type="button" onclick="console.log('previousSibling是'+this.previousSibling);" value="e" />
<!-- 这是个text对象,因为在这个标签元素前面是一个换行符 -->
<input id="a6" type="button" onclick="console.log(this.previousSibling);" value="e" />

<input id="a7" type="button" onclick="console.log('previousElementSibling是'+this.previousElementSibling);" value="e" />
<!-- 这是个标签元素,因为在这个js代码所取的是一个前一个标签对象 -->
<input id="a8" type="button" onclick="console.log(this.previousElementSibling);" value="e" />

四、场景实现

添加的实现:就是用vue中的v-for指令。点击按钮之后,在列表中加一个列表元素,就会重新渲染。

拖拽的实现:这里有两种可能性,一个是如果是往前拖拽,则所要拖拽元素放在目标元素之前;如果是往后拖拽,则所要拖拽元素放在目标元素之后。

因此需要判断目标元素是否是前面的元素。

isPreviousElements(sourse, target){
    //这里是判断前面是否还有元素,sourse是不是第一个元素
    if(!sourse.previousElementSibling){
        return false;
    }
    //这里是判断
    if(target.isEqualNode(sourse.previousElementSibling)){
        return true;
    }
    return this.isPreviousElements(sourse.previousElementSibling, target)
},

然后把标签元素放入到目标元素之前或之后。

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>todayTask</title>
    <script src="../js/vue.js"></script>
    <style>
        .task{
            width: 300px;
            height: 50px;
            list-style-type:decimal;
            list-style-position:inside;    
            cursor: grab;
            position: absolute;
            transition: top;
            transition-duration: 0.6s;
        }
        .taskList{
            position: relative;
            display: flex;
            flex-direction: column;
        }
        .addTask{
            display: block;
        }
    </style>
</head>
<body>
    <div class="container">
        <button class="addTask" @click="addTask">添加任务</button>
        <div class="taskList">
            <div class="task" draggable="true" @dragstart.self = "ondragstart($event)" @dragover.self = "ondragover($event)" v-for="task in tasks" :key="task.id">
                <span>
                    {{task.id}}
                    <input type="text" v-model="task.task">
                </span>
            </div>
        </div>
 
    </div>
</body>
<script>
    document.body.addEventListener("dragover",function(ev){
        ev.preventDefault();
    })
    new Vue({
        el:".container",
        data:{
            tasks:[
                {id:1,task:"",isDone:false}
            ],
            dragDiv:"",
            isMoving:false
        },
        methods:{
            addTask(){
                this.tasks.push({id:this.tasks.length+1,task:"",isDone:false})
                var taskList = document.getElementsByClassName("taskList")[0];
                taskList.style.height = this.tasks.length*50+"px"
            },
            sortDiv(divs){
                for(var i=0;i<divs.length;i++){
                    divs[i].style.top = i*50 + "px";
                }
            },
            isPreviousElements(sourse, target){
                //返回上一节点
                if(!sourse.previousElementSibling){
                    return false;
                }
            
                if(target.isEqualNode(sourse.previousElementSibling)){
                    return true;
                }
                return this.isPreviousElements(sourse.previousElementSibling, target)
            },
            ondragstart(ev){
                this.dragDiv = ev.target;
                console.log("dragstart");
            },
            ondragover(ev){
                overDrag = ev.target;
                console.log(overDrag.isEqualNode(this.dragDiv));
                console.log(this.isMoving);
                if(this.isMoving || overDrag.isEqualNode(this.dragDiv)){
                    return;
                }
                //判断是否是前一个标签元素
                if(this.isPreviousElements(overDrag,this.dragDiv)){
                    overDrag.parentNode.insertBefore(this.dragDiv,overDrag.nextElementSibling);
                }else{
                    overDrag.parentNode.insertBefore(this.dragDiv,overDrag);
                }
                this.isMoving = true;
                const self = this;
                var st = setTimeout(function(){
                    self.isMoving = false;
                    clearTimeout(st);
                },600);
                this.sortDiv(document.querySelectorAll(".task"));
            }
        },
        created(){
            //设置ul的盒子高度
            var taskList = document.getElementsByClassName("taskList")[0];
            taskList.style.height = this.tasks.length*50+"px";
            //设置每一个item的上边缘top
            this.sortDiv(document.querySelectorAll(".task"));
        },
        updated(){
            this.sortDiv(document.querySelectorAll(".task"));
        }
    })
 
</script>
</html>

总结 

到此这篇关于vue实现前端拖拽div位置交换的文章就介绍到这了,更多相关vue前端拖拽div位置交换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解vue项目中如何加载markdown

    详解vue项目中如何加载markdown

    这篇文章主要为大家详细介绍了在vue项目中如何加载markdown,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-11-11
  • Vue前后端不同端口的实现方法

    Vue前后端不同端口的实现方法

    今天小编就为大家分享一篇Vue前后端不同端口的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • el-checkbox-group 的v-model无法绑定对象数组的问题解决

    el-checkbox-group 的v-model无法绑定对象数组的问题解决

    elementUI官方文档中el-checkbox-group组件绑定的都为一维数组,本文主要介绍了解决el-checkbox-group 的v-model无法绑定对象数组,感兴趣的可以了解一下
    2023-05-05
  • vue实现二级导航栏效果

    vue实现二级导航栏效果

    这篇文章主要为大家详细介绍了vue实现二级导航栏效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • Vue中如何设置全局的cookie对象

    Vue中如何设置全局的cookie对象

    这篇文章主要介绍了Vue中如何设置全局的cookie对象,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • webpack中的optimization配置示例详解

    webpack中的optimization配置示例详解

    这篇文章主要介绍了webpack中的optimization配置详解,主要就是根据不同的策略来分割打包出来的bundle,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • 深入了解Vue3 中 this的使用

    深入了解Vue3 中 this的使用

    在Vue3中,this的使用方式与Vue2存在较大差异,尤其是在引入组合式API后,本文详细解析了Vue3中this的使用情况、底层源码和设计理念,并提供了面试技巧,感兴趣的可以了解一下
    2024-09-09
  • echarts3如何清空上一次加载的series数据

    echarts3如何清空上一次加载的series数据

    这篇文章主要介绍了echarts3如何清空上一次加载的series数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • vuex的辅助函数该如何使用

    vuex的辅助函数该如何使用

    vue通过辅助函数mapState、mapActions、mapMutations,把vuex.store中的属性映射到vue实例身上,这样在vue实例中就能访问vuex.store中的属性了,对于操作vuex.store就很方便了,本文具体的介绍下这些辅助函数的使用方法
    2021-06-06
  • el-popover如何通过js手动控制弹出框显示、隐藏

    el-popover如何通过js手动控制弹出框显示、隐藏

    最近项目中多次用到了Popover弹出框,下面这篇文章主要给大家介绍了关于el-popover如何通过js手动控制弹出框显示、隐藏的相关资料,需要的朋友可以参考下
    2023-12-12

最新评论