[英]Drag and Drop API stops working with custom MIME type on Android Chrome
問題: Android Chrome 上的拖放是否存在已知問題,或者我是否錯誤地使用了拖放 API? (如果兩者都不是,我將假設這是一個錯誤並向 Chrome 提交報告)。
問題:我正在實現一個簡單的拖放界面,該界面似乎工作正常,但在我正在測試的 3 個設備/瀏覽器組合中的 1 個上表現異常。 我已經確定問題出在我在draggable
元素的'dragstart'
事件上設置的自定義 MIME 類型'text/custom'
的規范中,但我在 Living Standard 或 MDN 上閱讀的內容都沒有領先我相信這應該是一個問題。
It works fine on Chrome on my desktop ( Windows 10, Chrome 97.0.4692.71
) and the iPhone 8 I'm testing ( iOS 15.0, Chrome 94.0.4606.76
), but fails on Chrome on my Galaxy S20 ( Android 11, Chrome 96.0.4664.104
)。
一旦我將draggable.setData(...)
中的 MIME 類型從'text/custom'
恢復為'text/plain'
,所有界面都會按預期工作,但如果可能的話,我希望有一個自定義 MIME 類型,而且我還沒有在網上找到任何能讓我相信我做不到的東西。
我為什么要關心?:我想了解最重要的是發生了什么,但嘗試使用自定義 MIME 類型的原因是為了擺脫container
上的各種'drag...'
處理程序(使用e.dataTransfer.types.includes('text/custom')
檢查)是否有可能偶然與我的界面交叉路徑的任何其他draggable
交互(例如:將文件從操作系統拖動到我頁面上的瀏覽器中或跨container
拖動鏈接/URL) .
代碼(盡可能剝離以最小化問題演示):
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<style>
#container {
display: flex;
justify-content: center;
align-items: center;
height: 150px;
width: 200px;
background-color: lightblue;
}
#draggable-tester {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
height: 40px;
width: 120px;
background-color: lightgreen;
}
</style>
</head>
<body>
<div id="container">Container</div>
<div id="draggable-tester" draggable="true">Draggable</div>
<script>
const draggableMimeType = 'text/custom';
// Initialize draggable element.
const draggable = document.getElementById('draggable-tester');
draggable.addEventListener('dragstart', (e) => {
e.dataTransfer.setData(draggableMimeType, 'data payload');
console.log('dragstart event fired on draggable');
});
draggable.addEventListener('dragend', () => {
console.log('dragend event fired on draggable');
});
// Initialize drag container and drop zone.
const dragContainer = document.getElementById('container');
dragContainer.addEventListener('dragenter', (e) => {
e.preventDefault();
console.log('dragenter event fired on container');
});
dragContainer.addEventListener('dragover', (e) => {
e.preventDefault();
});
dragContainer.addEventListener('drop', (e) => {
console.log(`drop w/ data: '${e.dataTransfer.getData(draggableMimeType)}'`);
});
</script>
</body>
結果:在桌面和 iPhone 上,當我在拖動容器上執行各種拖動操作並放下draggable
元素時,上面給出了預期的結果,但在 Android 上它只記錄'dragstart'
消息(它甚至不記錄'dragend'
在draggable
上注冊)。 一旦我將draggableMimeType
修改為'text/plain'
,它就可以按預期在所有設備上運行。
我認為這是一個錯誤。 我在這里提交了一個問題: https://bugs.chromium.org/p/chromium/issues/detail?id=1293803
與此同時,我正在通過完全回避拖放 API 的數據提供機制來解決這個問題。 顯然,您必須在dragstart
處理程序中調用setData()
才能使draggable
交互完全起作用,但我從不使用與getData
交互的另一半。
相反,我在各種事件處理程序中共享一點“全局”state(它僅在模塊內的幾十行中是全局的), dragstart
設置全局以容納我們當前正在拖動的元素和所有容器drag...
事件查看該全局以指示拖動是否與我們的自定義draggable
元素或來自野外的某些其他元素有關(例如:來自其他上下文/應用程序的文件或通過界面拖動的鏈接(在這種情況下,它只是退出))。 然后, dragend
負責將全局設置為undefined
,以便我們適當地維護是否應該由我們自己的邏輯處理拖動的指示。
一個小片段:
// Establish a global for tracking the in-house element currently being dragged.
let draggingElement = undefined;
// Initialize draggable element.
const draggable = document.getElementById('draggable-tester');
draggable.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', '');
draggingElement = draggable;
console.log('dragstart event fired on draggable');
});
draggable.addEventListener('dragend', () => {
draggingElement = undefined;
console.log('dragend event fired on draggable');
});
// Initialize drag container and drop zone.
const dragContainer = document.getElementById('container');
dragContainer.addEventListener('dragenter', (e) => {
if (!draggingElement) return;
e.preventDefault();
console.log('dragenter event fired on container');
});
dragContainer.addEventListener('dragover', (e) => {
if (!draggingElement) return;
e.preventDefault();
});
dragContainer.addEventListener('drop', () => {
if (!draggingElement) return;
console.log(`dropping element w/ id: "${draggingElement.getAttribute('id')}"`);
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.