项目中用到了panzoom组件(https://github.com/anvaka/panzoom),上面有一些绝对定位的dom元素,因为点击这些元素时,不能拖动画布,所以我需要模拟点击的当前dom节点,在没有缩放情况下,拖动是正常的,没有残影,也跟手,等按下alt键,滚动鼠标滑轮缩放后,在快速拖动节点,就会出现残影,且模拟的dom节点不跟手,请问怎么回事?
已处理:(偶尔还会有残影)
<template>
<div class="page-wrapper">
<div class="lft">
<div>left</div>
</div>
<div class="rht">
<div class="nodes-content-wrapper">
<div class="nodes-wrapper" id="nodes-wrapper">
<div
v-for="(node, idx) in nodes"
:key="`node-${idx}`"
class="node"
:style="{
width: `${node.width}px`,
height: `${node.height}px`,
left: `${node.x}px`,
top: `${node.y}px`,
}"
@mousedown="(e) => startDrag(e, node)"
>
<div class="node-inner-wrapper not-allowed-drag" :id="node.Id">
{{ node.Id }}
</div>
</div>
<!-- 影子节点 -->
<div
v-if="moveNode"
style="border: 1px solid blue"
class="node moni-node"
:style="{
width: `${moveNode.width}px`,
height: `${moveNode.height}px`,
left: `${moveNode.x}px`,
top: `${moveNode.y}px`,
zIndex: `${moveNodeZIndex}`,
}"
>
<div>{{ moveNode.Id }}</div>
<div>{{ moveNode.x }}</div>
<div>{{ moveNode.y }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import panzoom from "panzoom";
export default {
data() {
return {
pan: null,
nodes: [
{
Id: "Q",
x: 100,
y: 660,
width: 180,
height: 60,
},
{
Id: "G0",
x: 380,
y: 20,
width: 180,
height: 60,
},
{
Id: "G",
x: 380,
y: 227.5,
width: 180,
height: 60,
},
],
moveNodeZIndex: 300, //影子节点
moveNode: null, // 当前移动的节点
isDragging: false, // 是否正在拖动
offsetX: 0, // 鼠标点击node时,鼠标距离node左上角的偏移量
offsetY: 0, //
};
},
mounted() {
this.initPanZoom();
},
methods: {
initPanZoom(scale = 1, x = 0, y = 0) {
let that = this;
if (that.pan) {
that.pan.dispose();
}
const mainContainer = document.getElementById("nodes-wrapper");
let params = {
smoothScroll: false,
bounds: false, //可以移动出父容器
// autocenter: true,
zoomDoubleClickSpeed: 1,
minZoom: 0.5,
maxZoom: 3,
// overflow: 'auto',
// contain: 'outside',
beforeWheel: function (e) {
// 仅当 altKey 按下时才允许滚轮缩放。否则 - 忽略
var shouldIgnore = !e.altKey;
return shouldIgnore;
},
beforeMouseDown: function (e) {
// if(e.target.className == "not-allowed-drag") {
// console.log(e.offsetY, e.offsetX)
// }
if (e.target.className.indexOf("not-allowed-drag") == -1) {
return false;
}
return true;
},
};
that.pan = panzoom(mainContainer, params);
// //移动到目标位置(使用初始化参数initialX、initialY会基于 scale 改变——加上拖动到,top: 100; left: 200 的位置,如果 scale = 0.5,会给你还原到 50, 100 的位置。)
// that.pan.moveTo(x, y);
// 缩放时设置jsPlumb的缩放比率
that.pan.on("zoom", (e) => {
});
that.pan.on("panend", (e) => {});
},
/**
* 在节点上按下鼠标,准备拖拽
* @param {*} event
* @param {*} node
*/
startDrag(event, node) {
let that = this;
that.isDragging = true;
that.moveNode = JSON.parse(JSON.stringify(node));
that.moveNode.Id = `${that.moveNode.Id}_bak`;
//记住点击节点的位置(点击节点dom对象的坐标)
that.offsetX = event.offsetX
that.offsetY = event.offsetY
// 添加鼠标移动和松开的监听
document.addEventListener("mousemove", that.onDrag);
document.addEventListener("mouseup", that.stopDrag);
},
// 鼠标移动时更新 div 位置
onDrag(event) {
let that = this;
if (that.isDragging) {
// // 更新影子节点的位置,使其跟随鼠标
const transform = this.pan.getTransform(); // 获取当前的缩放和位移
const scale = transform.scale;
const mainContainer = document.getElementById("nodes-wrapper");
const rect = mainContainer.getBoundingClientRect()
const offsetX = event.clientX - rect.left;
const offsetY = event.clientY - rect.top;
const realOffsetX = offsetX / scale;
const realOffsetY = offsetY / scale;
this.moveNode.x = realOffsetX - that.offsetX
this.moveNode.y = realOffsetY - that.offsetY
}
},
// 鼠标松开时停止拖动
stopDrag() {
this.isDragging = false;
this.moveNode = null;
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.stopDrag);
},
},
};
</script>
<style scoped lang="scss">
.page-wrapper {
height: 100%;
display: flex;
.lft {
width: 300px;
}
.rht {
flex: 1;
}
}
.nodes-content-wrapper {
background: #f1f1f1;
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.nodes-wrapper {
background: #f5e4e4;
backface-visibility: hidden; //去掉残影
position: relative;
height: 100%;
width: 100%;
.node {
position: absolute;
border: 1px solid red;
user-select: none;
box-sizing: border-box;
.node-inner-wrapper {
position: relative;
height: 100%;
}
}
}
}
.plus-sub,
.plus-sib {
position: absolute;
font-size: 10px;
right: 0;
}
.plus-sub {
bottom: 0;
}
.plus-sib {
bottom: 20px;
}
.moni-node {
backface-visibility: hidden; //去掉残影
}
</style>