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

Обновление доступных целевых объектов после запуска dragstart в jquery.event.drag

Обзор:

У меня есть страница, которая использует jquery.event.drag и jquery.event.drop. Мне нужно иметь возможность перетаскивать элементы, которые постоянно добавляются в dom, даже после начала перетаскивания.


Проблема:

Когда событие dragstart срабатывает, он проверяет доступные целевые объекты и добавляет их в объект перетаскивания.

Проблема заключается в том, что я добавляю динамические объекты drop после того, как событие dragstart запущено, и поэтому пользователь не может отказаться от этих динамически добавленных целей возврата.


Пример:

http://jsfiddle.net/blowsie/36AJq/


Вопрос:

Как обновить перетаскивание, чтобы разрешить удаление элементов, которые были добавлены в dom после того, как началось перетаскивание?

4b9b3361

Ответ 1

Вы можете использовать этот фрагмент.

Важная функция: $.event.special.drop.locate();

Протестировано на chrome/safari/firefox/ie9 и, похоже, работает.

СМОТРЕТЬ ДЕМО


UPDATE

Для перекрытия событий см., работает ли следующий код. Я установил его внутри анонимной функции, чтобы избежать какой-либо глобальной переменной. Идея заключается в том, чтобы использовать свойство currentTarget события, чтобы проверить, не вызывает ли тот же самый элемент одно и то же событие. Я устанавливаю идентификатор элемента newdrop только для целей тестирования.

СМОТРЕТЬ ОБНОВЛЕНО ДЕМО

(function () {
    var $body = $("body"),
        newdrops = [],
        currentTarget = {},
        ondragstart = function () {

            $(this).css('opacity', .75);
        }, ondrag = function (ev, dd) {
            $(this).css({
                top: dd.offsetY,
                left: dd.offsetX
            });
        }, ondragend = function () {

            $(this).css('opacity', '');
            for (var i = 0, z = newdrops.length; i < z; i++)
            $(newdrops[i]).off('dropstart drop dropend').removeClass('tempdrop');
            newdrops = [];
        }, ondropstart = function (e) {
            if (currentTarget.dropstart === e.currentTarget) return;
            currentTarget.dropstart = e.currentTarget;
            currentTarget.dropend = null;
            console.log('start::' + e.currentTarget.id)
            $(this).addClass("active");
        }, ondrop = function () {
            $(this).toggleClass("dropped");
        }, ondropend = function (e) {
            if (currentTarget.dropend === e.currentTarget) return;
            currentTarget.dropend = e.currentTarget;
            currentTarget.dropstart = null;
            console.log('end::' + e.currentTarget.id)
            $(this).removeClass("active");
        };

    $body.on("dragstart", ".drag", ondragstart)
        .on("drag", ".drag", ondrag)
        .on("dragend", ".drag", ondragend)
        .on("dropstart", ".drop", ondropstart)
        .on("drop", ".drop", ondrop)
        .on("dropend", ".drop", ondropend);



    var cnt = 0;
    setInterval(function () {
        var dataDroppables = $body.data('dragdata')['interactions'] ? $body.data('dragdata')['interactions'][0]['droppable'] : [];

        var $newDrop = $('<div class="drop tempdrop" id="' + cnt + '">Drop</div>');
        cnt++;
        $("#dropWrap").append($newDrop);
        var offset = $newDrop.offset();
        var dropdata = {
            active: [],
            anyactive: 0,
            elem: $newDrop[0],
            index: $('.drop').length,
            location: {
                bottom: offset.top + $newDrop.height(),
                elem: $newDrop[0],
                height: $newDrop.height(),
                left: offset.left,
                right: offset.left + $newDrop.width,
                top: offset.top,
                width: $newDrop.width
            },
            related: 0,
            winner: 0
        };
        $newDrop.data('dropdata', dropdata);
        dataDroppables.push($newDrop[0]);
        $newDrop.on("dropstart", ondropstart)
            .on("drop", ondrop)
            .on("dropend", ondropend);
        $.event.special.drop.locate($newDrop[0], dropdata.index);
        newdrops.push($newDrop[0]);
    }, 1000);
})();

Ответ 2

Мне не удалось получить эту работу с помощью jquery.event.drag и jquery.event.drop, но я сделал ее работу с собственными событиями HTML5:

http://jsfiddle.net/R2B8V/1/

Решение заключалось в том, чтобы связать события с целями drop в функции и вызвать их для обновления привязок. Я подозреваю, что вы можете заставить это работать с jquery.event.drag и jquery.event.drop с использованием аналогичного принципала. Если я смогу получить работу, я обновлю свой ответ.

Вот JS:

$(function() {
    var bind_targets = function() {
        $(".drop").on({
            dragenter: function() {
                $(this).addClass("active");
                return true;
            },
            dragleave: function() {
                $(this).removeClass("active");
            },
            drop: function() {
                $(this).toggleClass("dropped");
            }
        });
    };    

    $("div[draggable]").on({
        dragstart: function(evt) {
            evt.originalEvent.dataTransfer.setData('Text', 'data');
        },
        dragend: function(evt) {
            $('.active.drop').removeClass('active');   
        }
    });
  setInterval(function () {
      $("#dropWrap").append('<div class="drop">Drop</div>');
      // Do something here to update the dd.available
      bind_targets();
  }, 1000)
});

Ответ 3

Вы не можете. На dragstart возможные зоны вылета рассчитываются из DOM и не могут быть отредактированы до dragend. Даже постоянное восстановление .on() (Demo: http://jsfiddle.net/36AJq/84/) не даст желаемого эффекта.

Я решил проблему немного по-другому. (Демо: http://jsfiddle.net/36AJq/87/)

  • Начните с каждого <div> в HTML.
  • Примените opacity: 0, чтобы сделать его невидимым, и width: 0, чтобы он не получал dropend при скрытии.
  • Используйте setInterval, чтобы показать следующий скрытый div ($('.drop:not(.visible)').first()) каждые 1000 мс.

JS:

$("body")
  .on("dragstart", ".drag", function () {
    $(this).css('opacity', .75);
  })
  .on("drag", ".drag", function (ev, dd) {
    $(this).css({
      top: dd.offsetY,
      left: dd.offsetX
    });
  })
  .on("dragend", ".drag", function () {
    $(this).css('opacity', '');
  })
  .on("dropstart", ".drop", function () {
    $(this).addClass("active");
  })
  .on("drop", ".drop", function () {
    $(this).toggleClass("dropped");
  })
  .on("dropend", ".drop", function () {
    $(this).removeClass("active");
  });
setInterval(function () {
    $('.drop:not(.visible)').first()
      .addClass('visible').removeClass('hidden');
}, 1000)

Ответ 5

Почему бы не поместить все div на страницу и не скрывать видимость? Затем используйте setInterval() для изменения каждой видимости каждую секунду.