我正在开发一个带有拖放功能的Web应用程序。到目前为止,我使用的是基本的HTML5拖动功能,但现在我切换到使用interact.js库。
我不知道我的问题是特定于这个库还是更一般的问题:拖放时的事件通常会触发多次(如果我没有看错的话,它似乎总是正好4次,但不能保证)。
我也使用Vue.js,这是我的代码:
<template>
<v-card
elevation="0"
:id="id"
class="board device-dropzone"
>
<slot class="row"/>
<div
Drop Card here
</div>
</v-card>
</template>
在槽中,添加了一个图像和带有文本的div。
<script>
import interact from 'interactjs';
export default {
name: 'Devices',
props: ['id', 'acceptsDrop'],
data() {
return {
extendedHover: false,
hoverEnter: false,
timer: null,
totalTime: 2,
};
},
methods: {
resetHover() {
alert('reset');
},
drop(e) {
let wantedId = e.relatedTarget.id.split('-')[0];
console.log(wantedId);
console.warn(e.target);
e.target.classList.remove('hover-drag-over');
this.extendedHover = false;
console.log('-------------dropped');
console.warn('dropped onto device');
this.$emit('dropped-component', cardId);
e.target.classList.remove('hover-drag-over'); */
},
dragenter() {
console.log('------------dragenter');
this.hoverEnter = true;
setTimeout(() => {
this.extendedHover = true;
console.log('extended hover detected');
}, 2000);
} */
this.timerID = setTimeout(this.countdown, 3000);
},
dragover(e) {
if (this.acceptsDrop) {
e.target.classList.add('hover-drag-over');
}
},
dragleave(e) {
if (this.acceptsDrop) {
clearInterval(this.timer);
this.timer = null;
this.totalTime = 2;
e.target.classList.remove('hover-drag-over');
this.extendedHover = false;
this.hoverEnter = false;
console.log('................');
console.warn(this.extendedHover);
// this.$emit('cancel-hover');
}
},
countdown() {
console.log('!!!!!!!!!!!!!!!!!!!!');
if (this.hoverEnter === true) {
this.extendedHover = true;
console.log('-------------------');
console.warn(this);
console.warn(this.extendedHover);
this.$emit('long-hover');
}
},
},
mounted() {
// enable draggables to be dropped into this
const dropzone = this;
interact('.device-dropzone').dropzone({
overlap: 0.9,
ondragenter: dropzone.dragenter(),
ondrop: function (event) {
dropzone.drop(event);
},
})
},
};
</script>
可拖动组件如下所示:
<template>
<v-card
class="primary draggable-card"
:id = "id"
:draggable = "false"
@dragover.stop
ref="interactElement"
>
<slot/>
</v-card>
使用脚本:
<script>
import interact from 'interactjs';
export default {
props: ['id', 'draggable'],
data() {
return {
isInteractAnimating: true,
position: { x: 0, y: 0 },
};
},
methods: {
/* dragStart: (e) => {
e.stopPropagation(); // so dragStart of ParentBoard does not get triggered as well
// eslint-disable-next-line
const target = e.target;
e.dataTransfer.setData('card_id', target.id);
e.dataTransfer.setData('type', 'widget');
// for some delay
setTimeout(() => {
console.log('started dragging');
}, 0);
}, */
dragEndListener: (event) => {
console.warn('+++++++++++++++++++++++++++');
// console.warn(event.currentTarget.id);
if (document.getElementById(event.currentTarget.id)) {
event.currentTarget.parentNode.removeChild(event.currentTarget);
}
},
dragMoveListener: (event) => {
/* eslint-disable */
var target = event.target;
// keep the dragged position in the data-x/data-y attributes
const xCurrent = parseFloat(target.getAttribute('data-x')) || 0;
const yCurrent = parseFloat(target.getAttribute('data-y')) || 0;
const valX = xCurrent + event.dx;
const valY = yCurrent + event.dy;
// translate the element
event.target.style.transform =
`translate(${valX}px, ${valY}px)`
// update the postion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
/* eslint-enable */
},
mounted() {
const element = this.$refs.interactElement;
console.log(element);
// interact(element).draggable({
const component = this;
interact('.draggable-card')
.draggable({
manualStart: true,
onmove: component.dragMoveListener,
onend:component.dragEndListener,
})
.on('move', function (event) {
var interaction = event.interaction;
// if the pointer was moved while being held down
// and an interaction hasn't started yet
if (interaction.pointerIsDown && !interaction.interacting()) {
var original = event.currentTarget;
// create a clone of the currentTarget element
const clone = event.currentTarget.cloneNode(true);
clone.id = clone.id + "-clone";
clone.classname += " dragged-clone";
// insert the clone to the page
document.body.appendChild(clone);
clone.style.opacity = 0.5;
// start a drag interaction targeting the clone
interaction.start({ name: 'drag' },
event.interactable,
clone);
}
})
.on('end', function (event) {
console.error('end drag');
});
},
/* eslint-enable */
};
</script>
一般来说,拖放是可以的。但是我不明白为什么,例如,当只拖放一张卡片时,拖放事件会触发四次。有人能帮我吗?
1条答案
按热度按时间vmdwslir1#
我在使用相同的框架和库时也遇到了类似的问题。由于有一些基于事件触发的逻辑,所以当它多次触发时,它正在破坏我的应用程序。
我怀疑该问题与bubbling of events有关。
因此,在我的例子中,解决方案是在
drop(event)
处理程序中添加event.stopImmediatePropagation()
。正如参考文章中提到的,在停止事件冒泡时应该注意不要在其他地方产生不可预见的后果。