问题
According to this answer, I should be able to get the element that an element "drop" occurred over. However, it's reporting really odd and random results which always seems to be parent elements instead of the actual child element the dragged element is dropped on.
Here's the FULL CODE EXAMPLE on CodeSandbox with the pertinent snippets shown below...
<div>
<div id="sidebar">
<drag :transfer-data="{ type: 'textbox', width: 330, height: 50 }" class="draggable-item"
>Textbox
<div slot="image" class="drag-image"><div class="field-container" style="width: 330px;height: 50px;">Texbox</div></div></drag
>
</div>
<div id="pages-container" @click.self="deselectAll();">
<b-alert show variant="info" class="text-center">Drag controls from the left sidebar to the pages below.</b-alert>
<drop
class="page-container"
v-for="(p, index) in pages"
@drop="onDrop"
@click.self="deselectAll();"
:data-page-number="p.pageNumber"
:key="p.pageNumber + '_page_' + index"
:style="{ width: p.width + 'px', height: p.height + 'px' }"
>
<img src="https://www.kirupa.com/flash/images/single_column_text.png" width="100%" height="100%" :data-page-number="p.pageNumber" @click.self="deselectAll();" />
<div style="position: absolute;top:0;bottom:0;left:0;right:0;background-color:white;opacity:0" :data-page-number="p.pageNumber" @click.self="deselectAll();"></div>
<vue-draggable-resizable
:id="f.id"
:style="{ 'z-index': '1044 !important' }"
:class="{ 'field-container grabbable': true, selected: f.isSelected }"
v-for="(f, f_index) in getPageFields(fields, p.pageNumber)"
:key="f.id"
:min-width="20"
:min-height="20"
:x="f.left"
:y="f.top"
:w="f.width"
:h="f.height"
:parent="false"
:z-index="f.isSelected ? '1045 !important' : '1044 !important'"
:prevent-deactivation="true"
:active.sync="f.isSelected"
@resizestop="onResizeStop"
@dragstop="onDragStop"
@activated="onActivated(f.id);"
@clicked="onActivated(f.id);"
>id: {{ f.id }} <br />
page: {{ p.pageNumber }} fieldIndex: {{ f_index }} selected: {{ f.isSelected }}</vue-draggable-resizable
>
</drop>
</div>
</div>
The pertinent JavaScript is shown here (the page number alert test is always undefined)...
onDragStop(x, y) {
//...
const el = document.elementFromPoint(x, y);
alert("Dropped onto page number: " + el.dataset.pageNumber);
}
回答1:
As @Joao pointed out, document.elementFromPoint() requires viewport coordinates, but VueDraggableResizable provides offset coordinates (based on its configured lock aspect ratio and bounds) relative to the initial drop-element. You could still get the viewport coordinates by grabbing them from the draggable item itself.
Steps:
Add a ref to
<vue-draggable-resizable>(which will create an array of references to the draggable), and update thedragstop-handler to also take an index that we'll use with the applicablerefin the next step:// template <vue-draggable-resizable v-for="(f, f_index) in ..." ref="draggable" 👈 @dragstop="(x,y) => onDragStop(x,y,f_index)" 👈 > // script onDragStop(x, y, 👉index) { ... }In the
dragstop-handler, disablepointer-eventson the referenced draggable $el (corresponding to the index from the previous step) so thatdocument.elementFromPoint()can grab the element underneath the draggable's viewport coordinates, which we'll get with getBoundingClientRect():onDragStop(x, y, index) { const draggable = this.$refs.draggable[index].$el; draggable.style.pointerEvents = 'none'👈 const { left: dragX, top: dragY } = draggable.getBoundingClientRect(); const targetElem = document.elementFromPoint(dragX, dragY); draggable.style.pointerEvents = 'auto' ... }
demo
来源:https://stackoverflow.com/questions/54928835/document-elementfrompointx-y-isnt-reporting-correct-child-elements