vue.js 3.2.20:拖动创建div及移动、缩放、删除等操作
一,演示项目的代码地址:
https://gitee.com/liuhongdi/move
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/28/vue-js-3-2-20-tuo-dong-chuang-jian-div-ji-yi-dong%e3%80%81-suo/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
或: https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,编写代码:
Home.vue
<template> <div class="main" > <div id="preview" style="float:left;background:url(/static/img/mao.jpeg);background-size:640px;width: 640px; height: 1290px; position: relative;background-color:#FF0004;" @mousedown="drawBegin($event)" @mousemove="drawMove($event)" @mouseup="drawEnd($event)"> </div> </div> </template> <script> export default { name: "Home", setup() { //let objX let objX=null; let objY=null; let setid=100; let isCDown = false; let curSetId = 0; function getOffsetTop(obj){ var tmp = obj.offsetTop; var val = obj.offsetParent; while(val != null){ tmp += val.offsetTop; val = val.offsetParent; } return tmp; } function getOffsetLeft(obj){ var tmp = obj.offsetLeft; var val = obj.offsetParent; while(val != null){ tmp += val.offsetLeft; val = val.offsetParent; } return tmp; } //创建div,开始按下鼠标 const drawBegin = (event) => { let id = event.srcElement.id; //console.log('id:'+id); if (id !== 'preview') { return; } var objTop = getOffsetTop(document.getElementById("preview"));//对象x位置 var objLeft = getOffsetLeft(document.getElementById("preview"));//对象y位置 var scrollTop = window.pageYOffset || document.documentElement.scrollTop ||document.body.scrollTop || 0; var mouseX = event.clientX+document.body.scrollLeft;//鼠标x位置 var mouseY = event.clientY+scrollTop;//鼠标y位置 //计算点击的相对位置 objX = mouseX-objLeft; objY = mouseY-objTop; //生成div var oDiv = document.createElement('div'); oDiv.style.position='absolute'; oDiv.style.top=objY+'px'; oDiv.style.left=objX+'px'; oDiv.style.border='2px solid #000000'; oDiv.style.background='#ffffff'; oDiv.style.opacity=0.7; oDiv.style.pointerEvents='none'; oDiv.dataset.origin_l = 0; oDiv.dataset.origin_t = 0; oDiv.dataset.origin_w = 0; oDiv.dataset.origin_h = 0; oDiv.id=setid; oDiv.style.zIndex=setid; document.getElementById("preview").appendChild(oDiv); } //创建div,移动中 const drawMove = (event) => { //如果在缩放div if (isCDown == true){ //var e = window.event || arguments.callee.caller.arguments[0]; let e = window.event; let nx = e.clientX; let ny = e.clientY; //console.log('nx:'+nx+";ny:"+ny); let nl = nx - cx; let nt = ny - cy; //console.log('nl:'+nl+";nt:"+nt); let destw = parseInt(origin_w)+nl; let desth = parseInt(origin_h)+nt; //console.log('destw:'+destw+";desth:"+desth); document.getElementById(curSetId).style.width = destw+"px"; document.getElementById(curSetId).style.height = desth+"px"; return; } //如果在移动div if (isDown == true){ let e = window.event; let nx = e.clientX; let ny = e.clientY; //计算移动后的左偏移量和顶部的偏移量 let nl = nx - (x - l); let nt = ny - (y - t); document.getElementById(curSetId).style.left = nl + 'px'; document.getElementById(curSetId).style.top = nt + 'px'; return; } //如果是在创建div时 if(objX!=null){ var objTop = getOffsetTop(document.getElementById("preview"));//对象x位置 var objLeft = getOffsetLeft(document.getElementById("preview"));//对象y位置 var scrollTop = window.pageYOffset || document.documentElement.scrollTop ||document.body.scrollTop || 0; var mouseX = event.clientX+document.body.scrollLeft;//鼠标x位置 var mouseY = event.clientY+scrollTop;//鼠标y位置 //计算点击的相对位置 let movingX = mouseX-objLeft; let movingY = mouseY-objTop; if(movingX>=objX){ document.getElementById(setid).style.width=movingX-objX+'px'; }else{ document.getElementById(setid).style.left=movingX+'px'; document.getElementById(setid).style.width=objX-movingX+'px'; } if(movingY>=objY){ document.getElementById(setid).style.height=movingY-objY+'px'; }else{ document.getElementById(setid).style.top=movingY+'px'; document.getElementById(setid).style.height=objY-movingY+'px'; } } } //创建div,停止移动,完成 const drawEnd = (event) => { console.log(event); objX=objY=null; if (isCDown == true){ return; } if (document.getElementById(setid) == null){ return; } if ('' == document.getElementById(setid).style.width || ''==document.getElementById(setid).style.height || '0px'==document.getElementById(setid).style.width || '0px'==document.getElementById(setid).style.height) { document.getElementById(setid).parentElement.removeChild(document.getElementById(setid)); return; } document.getElementById(setid).innerHTML = "<div id='inner"+setid+"' style='pointer-events:auto;width:100%;height:100%;' onMouseDown='divmousedown("+setid+")' onMouseUp='divmouseup("+setid+",0)' onMouseMove='divmousemoving("+setid+")' ></div>"; document.getElementById(setid).innerHTML += '<div id="coor'+setid+'" class="coor" onMouseDown="coormousedown('+setid+')" onMouseMove="coormousemoving('+setid+')" onMouseUp="coormouseup('+setid+',0)"></div>'; document.getElementById(setid).innerHTML += '<div id="edit'+setid+'" class="edit" onclick="edit('+setid+',0)">E</div>'; document.getElementById(setid).innerHTML += '<div id="del'+setid+'" class="del" onclick="del('+setid+')">X</div>'; setid++; } //coor module for div resize--------------------------------------------------------- //移动div let cx = 0; let cy = 0; let origin_w ; let origin_h ; //缩放div,coor按下鼠标,开始 const coormousedown = (setid) => { if (isCDown == true) { return false; } //计算点击的相对位置 var e = window.event ; //获取x坐标和y坐标 cx = e.clientX; cy = e.clientY; //获取左部和顶部的偏移量 origin_w = document.getElementById(setid).style.width; origin_h = document.getElementById(setid).style.height; isCDown = true; curSetId = setid; } //缩放div,coor松开 const coormouseup = (setid,content_id) => { console.log('===============coormouseup'); isCDown = false; var width = parseInt(document.getElementById(setid).style.width); var height = parseInt(document.getElementById(setid).style.height); if (content_id>0){ console.log("width:"+width+";origin_w:"+document.getElementById(setid).dataset.origin_w+";height:"+height+";origin_h:"+document.getElementById(setid).dataset.origin_h); if (width == document.getElementById(setid).dataset.origin_w && height == document.getElementById(setid).dataset.origin_h){ //未修改大小,do nothing } else { document.getElementById(setid).dataset.origin_w = width; document.getElementById(setid).dataset.origin_h = height; } } } //缩放div,coor移动中 const coormousemoving = (setid) => { if (isCDown == false){ return; } var e = window.event ; var nx = e.clientX; var ny = e.clientY; //计算移动后的左偏移量和顶部的偏移量 console.log('nx:'+nx+";ny:"+ny); var nl = nx - cx; var nt = ny - cy; var destw = parseInt(origin_w)+nl; var desth = parseInt(origin_h)+nt; //console.log('destw:'+destw+";desth:"+desth); document.getElementById(setid).style.width = destw+"px"; document.getElementById(setid).style.height = desth+"px"; } window.coormousedown = coormousedown; window.coormousemoving = coormousemoving; window.coormouseup = coormouseup; //移动div -----------------------------移动手动创建的div let x = 0; let y = 0; let l = 0; let t = 0; let isDown = false; let curDivId = 0; //移动div,按下鼠标,开始 const divmousedown = (id) => { if (isDown == true) { return false; } var e = window.event; //获取x坐标和y坐标 x = e.clientX; y = e.clientY; //获取左部和顶部的偏移量 l = document.getElementById(id).offsetLeft; t = document.getElementById(id).offsetTop; //开关打开 isDown = true; curSetId = id; curDivId = id; } //移动div,正在移动时 const divmousemoving = (id) => { if (id!=curDivId) { return; } var e = window.event ; if (isCDown == true){ let nx = e.clientX; let ny = e.clientY; console.log('nx:'+nx+";ny:"+ny); let nl = nx - cx; let nt = ny - cy; console.log('nl:'+nl+";nt:"+nt); var destw = parseInt(origin_w)+nl; var desth = parseInt(origin_h)+nt; console.log('destw:'+destw+";desth:"+desth); document.getElementById(curSetId).style.width = destw+"px"; document.getElementById(curSetId).style.height = desth+"px"; return; } if (isDown == false) { return; } //获取x和y let nx = e.clientX; let ny = e.clientY; //计算移动后的左偏移量和顶部的偏移量 let nl = nx - (x - l); let nt = ny - (y - t); document.getElementById(id).style.left = nl + 'px'; document.getElementById(id).style.top = nt + 'px'; } //移动div结束 const divmouseup = (setid,content_id) => { isDown = false; //得到它的位置: var left = parseInt(document.getElementById(setid).style.left); var top = parseInt(document.getElementById(setid).style.top); if (content_id>0) { if (left == document.getElementById(setid).dataset.origin_l && top == document.getElementById(setid).dataset.origin_t){ //未修改位置,do nothing } else { document.getElementById(setid).dataset.origin_l = left; document.getElementById(setid).dataset.origin_t = top; } } } window.divmousedown = divmousedown; window.divmousemoving = divmousemoving; window.divmouseup = divmouseup; //div的删除功能,加了一个淡出效果 const del = (idNumber) => { if (confirm("确认要删除当前div吗?"+idNumber)) { let delDom = document.getElementById(idNumber); delDom.style.opacity = 0; delDom.style.transition = "all 0.5s"; setTimeout(function () { document.getElementById("preview").removeChild(delDom); }, 520); } } window.del = del; //div的编辑功能,只写了一个alert const edit = (idNumber,contentId) => { alert("edit:"+idNumber+":content:"+contentId); } window.edit = edit; return { drawBegin, drawMove, drawEnd, coormousemoving, coormouseup, coormousedown, del, edit, } } } </script> <style scoped> .main { width:100vw; height:100vh; background: #ff0000; } /deep/ .coor {pointer-events:auto; width: 10px; height: 10px; overflow: hidden; cursor: se-resize; position: absolute; right: 0; bottom: 0; background-color: #00FFFF; z-index: 5000;} /deep/ .edit {pointer-events:auto; width: 18px; height: 18px;line-height: 18px; overflow: hidden; cursor: se-resize; position: absolute; left: 0px; bottom: -18px; text-align: center;background-color: #ADFF2F; } /deep/ .del {pointer-events:auto; width: 18px; height: 18px;line-height: 18px; overflow: hidden; cursor: se-resize; position: absolute; left: 18px; bottom: -18px;text-align: center; background-color: #09C; } /deep/ .number {pointer-events:auto; width: 18px; height: 18px;line-height: 18px; overflow: hidden; cursor: se-resize; position: absolute; left: 0px; top: -18px;text-align: center; background-color: #09C; } </style>
三,测试效果
四,查看vue的版本:
liuhongdi@lhdpc:/data/vue/move$ npm list vue move@0.1.0 /data/vue/move ├─┬ @vue/cli-plugin-babel@4.5.14 │ └─┬ @vue/babel-preset-app@4.5.14 │ └── vue@3.2.20 deduped └─┬ vue@3.2.20 └─┬ @vue/server-renderer@3.2.20 └── vue@3.2.20 deduped