javascript - 如何防止 Vuejs 中的 dragstart 出现短暂闪烁
问题描述
我正在尝试使 DIV 可拖动。除了在 startdrag 上闪烁的镜头外,这一切都很好。
这是问题的JSFiddle
以下是到目前为止的代码:
<template>
<div>
<div id="mydiv" :style="{ top: cordY + 'px', left: cordX + 'px' }">
<div id="mydivheader" draggable @dragstart="dragStart" @drag="dragging" @dragend="dragEnd">DRAG</div>
<p>BLA</p>
<p>BLA</p>
<p>BLA</p>
</div>
</div>
</template>
<script>
export default {
name: 'Home',
data () {
return {
cordY: 200,
cordX: 200,
divY: 0,
divX: 0
}
},
methods: {
dragStart: function (e) {
var img = new Image()
img.src = '../assets/nonexisting.png'
e.dataTransfer.setDragImage(img, 10, 10)
this.divX = e.pageX - e.target.getClientRects()[0].left
this.divY = e.pageY - e.target.getClientRects()[0].top
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
},
dragging: function (e) {
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
},
dragEnd: function (e) {
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
}
}
}
</script>
期望的结果是一个可拖动的元素,在开始时没有闪烁。
解决方案
您的解决方案在 Firefox 和 Chrome 中存在不同的问题。
在 Firefox中:你会遇到在dragstart时出现的闪烁问题,因为并且总是为零。查看firefox Bugzilla #505521了解更多详情。e.pageX|Y
e.clientX|Y
解决方法是在 document 上监听dragover事件,而不是在可拖动元素中拖动。
new Vue({
el: "#app",
data: {
cordY: 200,
cordX: 200,
divY: 0,
divX: 0,
delay: 20
},
mounted () {
document.addEventListener('dragover', this.dragover, false) // remember to remove the event listener before some-when like Vue.beforeDestroy.
},
methods: {
dragStart: function (e) {
// https://learnvue.co/2020/01/how-to-add-drag-and-drop-to-your-vuejs-project/
// HIDE GHOST/DRAG IMAGE BY REPLACING IT WITH A CUSTOM OR NONEXISTING IMAGE
var img = new Image()
img.src = 'data:image/jpeg;base64,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'
e.dataTransfer.setDragImage(img, 10, 10)
this.divX = e.pageX - e.target.getClientRects()[0].left
this.divY = e.pageY - e.target.getClientRects()[0].top
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
},
dragover: function (e) {
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
},
dragEnd: function (e) {
}
}
})
#mydiv {
position: absolute;
width:150px;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
resize: both;
overflow:auto
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<div id="mydiv" :style="{ top: cordY + 'px', left: cordX + 'px' }">
<div id="mydivheader" draggable @dragstart="dragStart" @dragend="dragEnd">DRAG</div>
<p>BLA</p>
<p>BLA</p>
<p>BLA</p>
</div>
</div>
</div>
在 Chrome中:使用一个setTimeout来控制帧速率将改善渲染。
你会发现如果 data property=this.delay
为 10 或更少,可拖动元素会更频繁地闪烁。如果 20 或更多,闪烁很少发生。
并且闪烁是由 DraggingEvent.pageX/Y return (0, 0) 有时在拖动结束前的最后一帧引起的。我在网上发现有人问过类似的问题,但没有很好的答案。
new Vue({
el: "#app",
data: {
cordY: 200,
cordX: 200,
divY: 0,
divX: 0,
timer: null,
delay: 20,
draging: false
},
methods: {
dragStart: function (e) {
// https://learnvue.co/2020/01/how-to-add-drag-and-drop-to-your-vuejs-project/
// HIDE GHOST/DRAG IMAGE BY REPLACING IT WITH A CUSTOM OR NONEXISTING IMAGE
var img = new Image()
img.src = 'data:image/jpeg;base64,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'
e.dataTransfer.setDragImage(img, 10, 10)
this.divX = e.pageX - e.target.getClientRects()[0].left
this.divY = e.pageY - e.target.getClientRects()[0].top
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
this.draging = true
},
dragging: function (e) {
if (this.timer) return;
this.timer = setTimeout(() => {
this.timer = null
if (!this.draging) return
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
}, this.delay)
},
dragEnd: function (e) {
this.draging = false
this.cordY = e.pageY - this.divY
this.cordX = e.pageX - this.divX
}
}
})
#mydiv {
position: absolute;
width:150px;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
resize: both;
overflow:auto
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<div id="mydiv" :style="{ top: cordY + 'px', left: cordX + 'px' }">
<div id="mydivheader" draggable @dragstart="dragStart" @drag="dragging" @dragend="dragEnd">DRAG</div>
<p>BLA</p>
<p>BLA</p>
<p>BLA</p>
</div>
</div>
</div>
下面是一张 gif,它显示了 DND 在 Chrome 中的工作方式:
正如我到目前为止所尝试的那样,使用Dragover解决方案似乎在 Chrome 和 Firefox 中都可以正常工作。
推荐阅读
- r - 如何根据三个不同变量的三个条件在df中选择一个值?
- java - 程序启动时清除java swing表单的所有文本字段
- apache-kafka - 在 Kafka 中轮询消费者组滞后于 HTTP
- r - 创建一个指示最大值的列
- azure - ApplicationInsight:在 Azure 门户上查看跟踪和错误的位置
- python - 如何对迭代器进行压缩?
- powershell - 为什么`Get-Help tree`显示`Pester`主题
- uicollectionview - 拖动 UICollectionViewCell 时如何实现透明背景或圆角
- ios - UIButton 导致无法识别的选择器发送到实例
- node.js - this.props.SignupUser 不是我的 SignupComponent 文件中的函数 有什么问题?