我正在使用 interact.js 和 Svelte 5(版本 5.0.0-next.200)来拖动最初位于可滚动 div 内部的元素,并且必须将其放置在该 div 的outside 处。为了完成这项工作,我需要克隆该元素,然后拖动克隆(据我所知,没有办法解决)。
现在,在以前的 Vanilla-js 项目中,我成功地改编了此 stackoverflow-answer 中的 代码 并且一切正常。但是,我无法让它在 Svelte 中工作。
下面是我的代码。我假设错误出现在
interaction.start({ name: 'drag' }, ev.interactable, clone);
中,它无法将拖动操作传递到克隆。
热烈欢迎任何帮助。几天来我一直在为此苦苦挣扎。
<script>
import interact from 'interactjs';
const dragElement = (ev) => {
const el = ev.target;
let x = (parseFloat(el.getAttribute('data-x')) || 0) + ev.dx;
let y = (parseFloat(el.getAttribute('data-y')) || 0) + ev.dy;
el.style.webkitTransform = el.style.transform = `translate(${x}px,${y}px)`;
el.setAttribute('data-x', x);
el.setAttribute('data-y', y);
}
const makeDraggable = (DRAG) => {
const draggable = document.querySelector('.draggable');
interact(draggable)
.draggable({
allowFrom: '*',
inertia: false,
autoScroll: false,
modifiers: [
interact.modifiers.restrict({
restriction: '#outer',
endOnly: true
})
],
onstart: (ev) => {
console.log('DRAG START of ', ev.target);
},
onmove: (ev) => {
console.log('DRAG MOVE of ', ev.target);
dragElement(ev);
},
onend: (ev) => {
console.log('DRAG END of ', ev.target);
DRAG.node.orig.style.opacity = 100; // show original again after drag
}
})
.on('move', (ev) => {
const el = ev.currentTarget;
const interaction = ev.interaction;
console.log('ON.MOVE TRY of ', el);
if (
interaction.pointerIsDown && // Only on active interaction
interaction.interacting() // Prevent activation by swiping through element
) {
// If ORIG then make a clone
if (
DRAG.active == false && // Create only one clone
el.getAttribute('isClone') == 'orig' // Prevent re-cloning clones
) {
DRAG.active = true;
console.log('CLONING START');
// Clone node and set its position
let clone = el.cloneNode(true);
clone.style.left = el.offsetLeft + 'px';
clone.style.top = el.offsetTop + 'px';
clone.style.position = 'absolute';
clone.setAttribute('isClone', 'clone');
clone.style.backgroundColor = 'grey';
// Append Clone and start drag interaction
document.querySelector('#outer').appendChild(clone);
console.log('CLONE IS READY: ', clone);
DRAG.node.orig = el;
DRAG.node.clone = clone;
DRAG.node.orig.style.opacity = 0; // hide original while dragging clone
interaction.start({ name: 'drag' }, ev.interactable, clone);
// if CLONE then drag
// } else if (el.getAttribute('isClone') == 'clone') {
// // console.log('MOVING THE CLONE START');
// // dragElement(ev);
// }
}
}
});
};
///////////////////////////////////////////////////////////////
// DRAG State
let DRAG = $state({
active: false,
node: {
orig: undefined,
clone: undefined
}
});
///////////////////////////////////////////////////////////////
// Handle drag
const handleDrag = () => {
makeDraggable(DRAG);
};
</script>
<div id="outer">
<h1>outer</h1>
<div id="inner">
<h1>inner (scrollable)</h1>
<div class="draggable" isClone="orig" use:handleDrag>Drag me</div>
</div>
</div>
<style>
#outer {
position: absolute;
background-color: yellow;
height: 95vh;
width: 90vw;
}
#inner {
position: absolute;
height: 400px;
width: 100%;
background: lightblue;
overflow-y: scroll;
}
.draggable {
position: absolute;
background-color: black;
color: white;
height: 500px;
width: 150px;
}
</style>
在
interaction.stop();
之前添加 interaction.start(...);
可以让您移动克隆体。
请注意,Svelte 5 对 DOM 结构操作很敏感 - 它已经与某些拖放库不兼容。