it-roy-ru.com

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's not my issue.
    dataTransferValue = e.originalEvent.dataTransfer.getData("text/plain");

    console.log(dataTransferValue);
};

Насколько я могу судить, это должно прекрасно работать, и если вы посмотрите на консоль при перетаскивании элемента, вы увидите записанный идентификатор, что означает, что он просто находит элемент и получает его атрибут id. Вопрос в том, просто не устанавливает данные или не получает данные?

Буду признателен за предложения, потому что после недели работы над этим с тремя попытками и более чем 200 версиями я начинаю сходить с ума. Все, что я знаю, это то, что он работал в версии 60 или около того, и этот конкретный код не изменился вообще ...

На самом деле, одно из основных отличий между 6X и 124 заключается в том, что я изменил привязку событий с live() на on(). Я не думаю, что это проблема, но я столкнулся с парой сбоев в Chrome, когда дело касается DnD. Это было опровергнуто. Метод привязки событий не влияет на проблему.

ОБНОВЛЕНИЕ

Я создал новый JSFiddle , который удаляет абсолютно все и просто оставляет привязку событий и обработчиков. Я протестировал его с jQuery 1.7.2 и 1.8 с on() и live(). Проблема сохранилась, поэтому я опустил уровень, удалил все фреймворки и использовал чистый JavaScript. Проблема все еще сохранялась, поэтому, основываясь на моем тестировании, это не мой код, который дает сбой. Вместо этого кажется, что Chrome, Safari и Opera все реализуют или setData() или getData() вне спецификации, или просто по какой-то причине отказывают. Пожалуйста, поправьте меня, если я ошибаюсь.

В любом случае, если вы посмотрите на новый JSFiddle, вы сможете повторить проблему, просто посмотрите на консоль, когда перетаскиваете элемент, предназначенный для принятия отбрасывания. Я пошел вперед и открыл билет с Chromium . В конце концов, я все еще могу делать что-то не так, но я просто не знаю, как еще сделать DnD на этом этапе. Новый JSFiddle настолько урезан, насколько это возможно ...

35
Gup3rSuR4c

Итак, после еще нескольких копаний я обнаружил, что проблема на самом деле не в Chrome, Safari и Opera. То, что выдало это, было то, что Firefox поддерживал это, и я просто не мог сказать, что другие браузеры терпят неудачу, так как это то, что я обычно принимаю для IE.

Истинная причина проблемы - сама спецификация DnD . В соответствии со спецификацией для событий drag, dragenter, dragleave, dragover и dragend режим хранения данных перетаскивания - защищенный режим. Что такое защищенный режим, спросите вы? Это:

Для всех других событий. Форматы и виды в хранилище данных перетаскивания Список элементов, представляющих перетаскиваемые данные, может быть перечислен, но сами данные недоступны и новые данные не могут быть добавлены.

Это означает, что «у вас нет доступа к заданным данным, даже в режиме« только чтение »!. В самом деле? Кто такой гений, который придумал это?

Теперь, чтобы обойти это ограничение, у вас есть несколько вариантов, и я только обрисую два, которые я придумал. Ваш первый - использовать злую глобальную переменную и загрязнять глобальное пространство имен. Ваш второй выбор - использовать HTML5 localStorage API для выполнения ТОЧНОЙ функциональности, которую должен был обеспечить DnD API для начала!

Если вы пойдете по этому пути, который у меня есть, вы теперь реализуете два API-интерфейса HTML5 не потому, что вы хотите, а потому, что вы имеете. Теперь я начинаю ценить РПК рассказывает о катастрофе , что такое HTML5 DnD API.

Суть в том, что спецификацию необходимо изменить, чтобы обеспечить доступ к хранимым данным, даже если это только в режиме только для чтения. В моем случае, с этим JSFiddle , я на самом деле использую dragenter как способ заглянуть в зону перетаскивания и убедиться, что я должен допустить, чтобы сброс происходил или нет.

В этом случае Mozilla явно отказалась от полного соответствия спецификации, поэтому мой JSFiddle работал в нем просто отлично. Просто так получилось, что я полностью поддерживаю не поддержку полной спецификации.

65
Gup3rSuR4c

Есть причина для «защищенного» бита ... перетаскивание может охватывать совершенно разные окна, и они не хотели, чтобы кто-то мог реализовать DIV «слушателя», который бы прослушивал содержимое всего, что было перетащил через него (и, возможно, отправил это содержимое AJAX на какой-нибудь шпионский сервер в Эльбонии). Только область DROP (которая более четко находится под контролем пользователя) получает полный объем.

Раздражает, но я понимаю, почему это может быть сочтено необходимым.

15
Jens Fiederer
var dragStartHandler = function (e) {
    e.originalEvent.dataTransfer.effectAllowed = "move";
    e.originalEvent.dataTransfer.setData("text/plain", this.id);
};

Проблема с «текст/обычный». Стандартной спецификацией в документации MSDN для setData является просто «текст» (без/plain). Chrome принимает/plain, но IE нет, в любой версии, которую я пробовал.

Я боролся с той же проблемой в течение нескольких недель, пытаясь выяснить, почему мои события «drop» не запускались должным образом в IE, в то время как в CHrome. Это было потому, что данные dataTransfer не были загружены должным образом.

12
Roland

Я знаю, что вы уже ответили на это, но это полезная тема - я просто хотел добавить здесь дополнение - если вы сами настраиваете данные, вы всегда можете добавить данные в само поле (безобразно, я знаю), но это предотвращает необходимость повторного создания функциональности:

Например, если вы устанавливаете свои собственные данные:

  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
ansiart

Стоит также отметить, что если вы покинете цепочку выполнения, используя тайм-аут, объект 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);
}
2
Nate Bosscher

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

1
Joshua Espana

Я получаю ту же ошибку для приведенного ниже кода:

event.originalEvent.dataTransfer.setData ("text/plain", event.target.getAttribute ('id'));

Я изменил код на: 

event.originalEvent.dataTransfer.effectAllowed = "move"; event.originalEvent.dataTransfer.setData ("текст", event.target.getAttribute ('id'));

И это сработало для меня.

1
RoshanZ