如何使 onPaste 事件与可拖动的 HTML 元素一起工作?

问题描述 投票:0回答:1

似乎

onPaste
事件无论出于何种原因都不会在可拖动元素上触发...(在 Firefox 和 Chrome 上检查)

是否有某种方法(无论是否黑客)可以使其发挥作用?

我一直在尝试:

  • 添加
    contenteditable="true"
    但这会破坏用户体验,因为我不希望用户实际编辑内容
  • 添加透明/不可见输入或内容可编辑元素,但这会破坏粘贴事件或可拖动
  • 仅在
    onMouseDown
    上使可拖动为 true,在
    onMouseUp
    上为 false,但粘贴事件仍然失败
  • 用paste将可拖动元素包裹成一个元素,用paste将元素包裹成可拖动元素,仍然失败...

这是我为重现问题而制作的一个最小示例:playground

Vue.createApp({
  setup() {
    const pasteEvents = Vue.ref([]);

    async function onPaste(event) {
      console.log(event);
      pasteEvents.value.push("Paste from Element " + event.target.dataset["element"])
    }

    return {
      pasteEvents,
      onPaste
    }
  }
}).mount("#app");
.wrapper {
  display: flex;
  flex-direction: column;
  gap: 16px;
  .paste-area {
    padding: 16px;
    background: #00000011;
    &:focus {
      border: 2px dashed red;
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>

<div id="app">
  <div class="wrapper">
    Click on an element and press Ctrl+V
    <div :draggable="true">
      <div class="paste-area" data-element="A" tabindex="0" @paste="onPaste">
        Element A (draggable)
      </div>
    </div>
    <div class="paste-area" tabindex="0" data-element="B" @paste="onPaste">
      Element B (no draggable)
    </div>
    {{ pasteEvents }}
  </div>
</div>

(这是一个vue游乐场,但它没有改变任何东西)

游乐场有趣的部分:

<div
    draggable="true"
    tabindex="0"
    @paste="onPaste"
>
    Element A (draggable, does not work)
</div>
<div
    tabindex="0"
    @paste="onPaste"
>
    Element B (no draggable, works)
</div>

(对于那些不熟悉 Vue 的人来说,

@paste
基本上就是
addEventListener("paste", () => ...)

在第一个元素上按

Ctrl+V
不会触发
paste
功能,但在第二个元素上可以正常工作。

编辑:似乎每个 ClipboardEvent 都一样(复制/剪切/粘贴)

javascript html paste
1个回答
0
投票

我在规范中找不到任何在这种情况下不会触发的原因,焦点元素设置得很好并且键盘事件在它们应该触发的地方触发,但话又说回来,我发现 W3C 的剪贴板规范的规范松散,就像他们的许多 UI 规范一样...

一种解决方法是实际设置

contenteditable
,然后通过侦听
beforeinput
事件来阻止用户进行任何编辑。
如果你想去掉插入符号,虽然你不能,但你至少可以通过将
caret-color
设置为透明来“隐藏”它。

// Sorry I don't know Vue enough to make it there
document.addEventListener("beforeinput", (evt) => {
  // You may need to adjust the selector
  if (evt.target.closest("[draggable='true'] [contenteditable]")) {
    evt.preventDefault();
  }
});

Vue.createApp({
  setup() {
    const pasteEvents = Vue.ref([]);

    async function onPaste(event) {
      console.log(event);
      pasteEvents.value.push("Paste from Element " + event.target.dataset["element"])
    }

    return {
      pasteEvents,
      onPaste
    }
  }
}).mount("#app");
.wrapper {
  display: flex;
  flex-direction: column;
  gap: 16px;
  .paste-area {
    padding: 16px;
    background: #00000011;
    /* added a few more specific selectors to handle focus in contenteditable */
    &:focus,&:focus-visible,&:focus-within {
      border: 2px dashed red;
      outline: 0;
    }
  }
}
/* You may need to adjust the selector */
[draggable="true"] [contenteditable] {
  caret-color: transparent;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.8/vue.global.min.js"></script>

<div id="app">
  <div class="wrapper">
    Click on an element and press Ctrl+V
    <div :draggable="true">
      <div :contenteditable class="paste-area" data-element="A" tabindex="0" @paste="onPaste">
        Element A (draggable)
      </div>
    </div>
    <div class="paste-area" tabindex="0" data-element="B" @paste="onPaste">
      Element B (no draggable)
    </div>
    {{ pasteEvents }}
  </div>
</div>

现在唯一可见的区别是光标实际上仍然在这里,因此如果您执行Shift箭头,将从光标的位置选择文本。如果这确实是一个问题,您可以通过监听

selectionchange
事件来解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.