拖放 API 在 Android Chrome 上停止使用自定义 MIME 类型
Drag and Drop API stops working with custom MIME type on Android Chrome
问题: Android Chrome 上的拖放是否存在已知问题,或者我是否错误地使用了拖放 API ? (如果两者都不是,我将假设这是一个错误并向 Chrome 提交报告)。
问题: 我正在实现一个简单的拖放界面,它似乎工作正常,但在我的 3 个 device/browser 组合中有一个表现异常正在测试。我确定问题出在我在 draggable
元素的 'dragstart'
事件上设置的自定义 MIME 类型 'text/custom'
的规范中,但我在 Living 中没有看到任何内容标准或 MDN 使我相信这应该是个问题。
它在我的桌面 (Windows 10, Chrome 97.0.4692.71
) 上的 Chrome 和我正在测试的 iPhone 8 (iOS 15.0, Chrome 94.0.4606.76
) 上运行良好,但在 [=67] 上运行失败=] 在我的 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
交互(例如:从 OS 进入我页面上的浏览器或将 link/URL 拖过 container
).
代码(尽可能多地剥离以最小化问题演示):
<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'
消息(它甚至不记录在 draggable
上注册的 'dragend'
)。只要我将 draggableMimeType
修改为 'text/plain'
,它就会按预期在所有设备上运行。
我认为这是一个错误。我在这里提交了一个问题:https://bugs.chromium.org/p/chromium/issues/detail?id=1293803
同时,我正在通过完全回避拖放 API 的数据提供机制来解决这个问题。显然,您必须在 dragstart
处理程序中调用 setData()
才能使 draggable
交互正常工作,但我从未利用与 getData
交互的另一半。
相反,我在各种事件处理程序中共享了一些“全局”状态(它只在模块内的几十行中是全局的),dragstart
将全局设置为 house我们当前正在拖动的元素和所有容器 drag...
事件都在查看该全局以指示拖动是否属于我们的自定义 draggable
元素或来自野外的其他元素(例如:来自其他 contexts/applications 的文件或通过界面拖动的链接(在这种情况下,它会退出)。 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')}"`);
});
问题: Android Chrome 上的拖放是否存在已知问题,或者我是否错误地使用了拖放 API ? (如果两者都不是,我将假设这是一个错误并向 Chrome 提交报告)。
问题: 我正在实现一个简单的拖放界面,它似乎工作正常,但在我的 3 个 device/browser 组合中有一个表现异常正在测试。我确定问题出在我在 draggable
元素的 'dragstart'
事件上设置的自定义 MIME 类型 'text/custom'
的规范中,但我在 Living 中没有看到任何内容标准或 MDN 使我相信这应该是个问题。
它在我的桌面 (Windows 10, Chrome 97.0.4692.71
) 上的 Chrome 和我正在测试的 iPhone 8 (iOS 15.0, Chrome 94.0.4606.76
) 上运行良好,但在 [=67] 上运行失败=] 在我的 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
交互(例如:从 OS 进入我页面上的浏览器或将 link/URL 拖过 container
).
代码(尽可能多地剥离以最小化问题演示):
<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'
消息(它甚至不记录在 draggable
上注册的 'dragend'
)。只要我将 draggableMimeType
修改为 'text/plain'
,它就会按预期在所有设备上运行。
我认为这是一个错误。我在这里提交了一个问题:https://bugs.chromium.org/p/chromium/issues/detail?id=1293803
同时,我正在通过完全回避拖放 API 的数据提供机制来解决这个问题。显然,您必须在 dragstart
处理程序中调用 setData()
才能使 draggable
交互正常工作,但我从未利用与 getData
交互的另一半。
相反,我在各种事件处理程序中共享了一些“全局”状态(它只在模块内的几十行中是全局的),dragstart
将全局设置为 house我们当前正在拖动的元素和所有容器 drag...
事件都在查看该全局以指示拖动是否属于我们的自定义 draggable
元素或来自野外的其他元素(例如:来自其他 contexts/applications 的文件或通过界面拖动的链接(在这种情况下,它会退出)。 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')}"`);
});