似乎
onPaste
事件无论出于何种原因都不会在可拖动元素上触发...(在 Firefox 和 Chrome 上检查)
是否有某种方法(无论是否黑客)可以使其发挥作用?
我一直在尝试:
contenteditable="true"
但这会破坏用户体验,因为我不希望用户实际编辑内容onMouseDown
上使可拖动为 true,在 onMouseUp
上为 false,但粘贴事件仍然失败这是我为重现问题而制作的一个最小示例: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 都一样(复制/剪切/粘贴)
我在规范中找不到任何在这种情况下不会触发的原因,焦点元素设置得很好并且键盘事件在它们应该触发的地方触发,但话又说回来,我发现 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
事件来解决这个问题。