Подтвердить что ты не робот

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 настолько урезан, насколько это возможно...

4b9b3361

Ответ 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. Я не проверял больше нигде, и я не уверен, почему это сработало. Надеюсь, что это поможет, и, надеюсь, кто-то может дать объяснение.