vue实现前端拖拽div位置交换的方法详解
一、场景描述
类似备忘录,点击添加按钮,多一条条目。然后手动拖拽条目可以更换条目之前的位置。
二、问题拆解
这里可以分成两个问题,第一个是添加,第二个是拖拽。
添加的实现: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位置交换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
el-checkbox-group 的v-model无法绑定对象数组的问题解决
elementUI官方文档中el-checkbox-group组件绑定的都为一维数组,本文主要介绍了解决el-checkbox-group 的v-model无法绑定对象数组,感兴趣的可以了解一下2023-05-05
最新评论