HTML5 DnD dataTransfer setData или getData не работают в каждом браузере, кроме Firefox
Рассмотрим этот JSFiddle. Он отлично работает в Firefox (14.0.1), но не работает в Chrome (21.0.1180.75), Safari (?) И Opera (12.01?) Как на Windows (7), так и на OS X (10.8). Насколько я могу судить, проблема связана с методами setData()
или getData()
объекта dataTransfer
. Вот соответствующий код из JSFiddle.
var dragStartHandler = function (e) {
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.setData("text/plain", this.id);
};
var dragEnterHandler = function (e) {
// dataTransferValue is a global variable declared higher up.
// No, I don't want to hear about why global variables are evil,
// that not my issue.
dataTransferValue = e.originalEvent.dataTransfer.getData("text/plain");
console.log(dataTransferValue);
};
Насколько я могу судить, это должно работать отлично, и если вы посмотрите на консоль, перетаскивая элемент, вы увидите выписанный идентификатор, а это значит, что он очень хорошо находит элемент и захватывает его атрибут id. Вопрос в том, что он просто не устанавливает данные или не получает данные?
Я был бы признателен за предложения, потому что после недели работы над этим с тремя попытками и более чем 200 + версиями, я начинаю терять сознание. Все, что я знаю, оно используется для работы в версии 60 или около того, и что конкретный код не изменился вообще...
На самом деле, одно из основных различий между 6X и 124 заключается в том, что я изменил привязку события от live()
до on()
. Я не думаю, что проблема, но я пришел, чтобы увидеть пару неудач из Chrome, когда речь заходит о DnD, работая над этим. Это было развенчано. Метод привязки событий не влияет на проблему.
UPDATE
Я создал новый JSFiddle, который полностью удаляет все и просто оставляет привязку события и обработчики. Я тестировал его с помощью jQuery 1.7.2 и 1.8 с on()
и live()
. Проблема продолжалась, поэтому я сбросил уровень и удалил все фреймворки и использовал чистый JavaScript. Проблема все еще сохранялась, поэтому на основании моего тестирования это не мой код, который не работает. Вместо этого выясняется, что Chrome, Safari и Opera реализуют либо setData()
, либо getData()
off spec, либо просто по какой-то причине не работают. Пожалуйста, поправьте меня, если я ошибаюсь.
В любом случае, если вы посмотрите на новый JSFiddle, вы сможете реплицировать проблему, просто посмотрите на консоль, когда перетаскиваете элемент, назначенный для принятия капли. Я пошел вперед и открыл билет Chromium. В конце концов, я все еще могу делать что-то неправильно, но я просто не знаю, как еще сделать DnD на данный момент. Новый JSFiddle настолько урезан, насколько это возможно...
Ответы
Ответ 1
Хорошо, поэтому после немного большего количества копаний я обнаружил, что проблема на самом деле не в Chrome, Safari и Opera. Что это дало, так это то, что Firefox поддерживал его, и я просто не мог сказать, что другие браузеры терпят неудачу, поскольку это то, что я обычно принимаю для IE.
Настоящей причиной проблемы является сама спецификация DnD. Согласно спецификации для событий drag
, dragenter
, dragleave
, dragover
и dragend
режим хранения данных перетаскивания является защищенным режимом. Что такое защищенный режим? Это:
Для всех других событий. Форматы и виды в хранилище данных перетаскивания список элементов, представляющих перетаскиваемые данные, можно перечислить, но сами данные недоступны, и новые данные не могут быть добавлены.
Это означает, что "у вас нет доступа к данным, которые вы установили, даже в режиме только для чтения! Go f @& # yourself.". В самом деле? Кто гений, который придумал это?
Теперь, чтобы обойти это ограничение, у вас мало вариантов, и я только собираюсь изложить два, которые я придумал. Ваш первый - использовать злую глобальную переменную и загрязнить глобальное пространство имен. Ваш второй выбор - использовать API-интерфейс HTML5 localStorage для выполнения ТОЧНОЙ той же функциональности, которую должен был предоставить API DnD для начала!
Если вы спуститесь по этому маршруту, который у меня есть, вы теперь реализуете два API HTML5 не потому, что хотите, а потому, что вам нужно. Теперь я начинаю ценить PPK разглагольствования о катастрофе, что API-интерфейс HTML5.
В нижней строке это, спецификация должна быть изменена, чтобы обеспечить доступ к сохраненным данным, даже если это только в режиме только для чтения. В моем случае с этим JSFiddle, я фактически использую dragenter
как способ взглянуть в зону перетаскивания и убедиться, что я должен разрешить происходят или нет.
В этом случае Mozilla, по-видимому, отказалась от полного соответствия спецификации, поэтому мой JSFiddle работал в нем очень хорошо. Так получилось, что это единственный раз, когда я полностью поддерживаю поддержку полной спецификации.
Ответ 2
Есть причина для "защищенного" бита.... drag/drop может охватывать совершенно разные окна, и они не хотели, чтобы кто-то мог реализовать "прослушиватель" DIV, который будет подслушивать содержание все, что было перетащино через него (и, возможно, отправить эти данные AJAX на какой-то шпионский сервер в Elbonia). Только область DROP (которая более четко под контролем пользователя) получает полный совок.
Раздражает, но я могу понять, почему это можно считать необходимым.
Ответ 3
var dragStartHandler = function (e) {
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.setData("text/plain", this.id);
};
Проблема заключается в "text/plain". Стандартная спецификация в документации MSDN для setData - это просто "текст" (без/plain). Chrome принимает /plain, но IE не делает, в любой версии, которую я пробовал.
Я боролся с той же проблемой в течение нескольких недель, пытаясь понять, почему мои "капли" события не срабатывали должным образом в IE, пока они делали в Хроме. Это произошло потому, что данные dataTransfer не были правильно загружены.
Ответ 4
Я знаю, что вы уже ответили на это, но это полезный поток - я просто хотел добавить добавление здесь - если вы сами устанавливаете данные, вы всегда можете добавить данные в самое поле (уродливое я знать), но это предотвращает необходимость повторного создания функциональных возможностей:
Например, если вы настраиваете собственные пользовательские данные:
dataTransfer.setData('mycustom/whatever', 'data');
добавьте данные в виде нового ввода данных и итерации:
dataTransfer.setData('mycustom/whatever/data/{a json encoded string even}');
Запросы
// naive webkit only look at the datatransfer.types
if (dataTransfer.types.indexOf('mycustom/whatever') >= 0) {
var dataTest = 'mycustom/whatever/data/';
// loop through types and create a map
for (var i in types) {
if (types[i].substr(0, dataTest.length) == dataTest) {
// shows:
// {a json encoded string even}
console.log('data:', types[i].substr(dataTest.length));
return; // your custom handler
}
}
}
проверено только на хром
Ответ 5
Также стоит отметить, что если вы оставите цепочку выполнения с использованием тайм-аута, объект dataTransfer больше не будет иметь ваши данные.
например.
function dropEventHandler(event){
var dt = event.dataTransfer.getData("text/plain"); // works
var myEvent = event;
setTimeout(function(){
var dt = myEvent.dataTranfer.getData("text/plain"); // null
}, 1);
}
Ответ 6
Я получал такую же ошибку для кода ниже:
event.originalEvent.dataTransfer.setData( "текст/обычный", event.target.getAttribute( 'ID'));
I Изменен код:
event.originalEvent.dataTransfer.effectAllowed = "move"; event.originalEvent.dataTransfer.setData( "text", event.target.getAttribute('id'));
И это сработало для меня.
Ответ 7
Я наткнулся на этот пост, потому что у меня был похожий опыт работы с функциями Chrome dataTransfer.setData()
и dataTransfer.getData()
.
У меня был код, который выглядел примерно так:
HTML:
<div ondragstart="drag(event)" ondrop="newDrop(event)"></div>
JAVASCRIPT:
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function newDrop(ev){
var itemDragged = ev.dataTransfer.getData("text");
var toDropTo = ev.target.id;
}
Код прекрасно работал в Internet Explorer, но когда он был протестирован в Chrome, я не смог получить значения, установленные в моем объекте dataTransfer
(в функции перетаскивания), используя функцию dataTransfer.getData()
функции newDrop. Мне также не удалось получить значение идентификатора из оператора ev.target.id
.
Немного покопавшись в Интернете, я обнаружил, что должен был использовать свойство currentTarget
параметров события, а не свойство target
событий. Обновленный код выглядел примерно так:
JAVASCRIPT:
function drag(ev) {
ev.dataTransfer.setData("text", ev.currentTarget.id);
}
function newDrop(ev){
var itemDragged = ev.dataTransfer.getData("text");
var toDropTo = ev.currentTarget.id;
}
С этим изменением я смог использовать функции dataTransfer.setData()
и dataTransfer.getData()
в chrome, а также в Internet Explorer. Я не проверял больше нигде, и я не уверен, почему это сработало. Надеюсь, что это поможет, и, надеюсь, кто-то может дать объяснение.