Drag & Drop с использованием HTML5

Владимир | | HTML, JavaScript, Web разработка.

html5 drag drop

К сожалению, на сегодняшний день использовать HTML5 довольно сложно. Стандарт в состоянии разработки и далеко не все браузеры поддерживают его возможности. Тем не менее, интересных нововведений в нём много и о них полезно знать. Поэтому сегодня я расскажу о моих экспериментах с перетаскиванием объектов (Drag & Drop).

Хочу предупредить. Приведённый ниже код работает в последних версиях Firefox и Google Chrome, в IE8 и Opera поддержка этих возможностей отсутствует.

Сразу даю ссылки на демонстрационную страничку и архив с примером.

Source

Чтобы просто разобраться с принципом работы D&D я решил сделать страничку с текстовыми блоками, которые можно будет перетаскивать из одного контейнера в другой.

Сама страница (index.html) имеет следующую разметку.

<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8>
    <title>HTML5 Drag & Drop</title>
    <link rel="stylesheet" href="styles.css">
    <script src="jquery-1.4.2.min.js"></script>
    <script src="init.js"></script>
</head>
<body>
    <div class="wrapper">
        <div id="block1">
            <div class="textBlock">Текст 1</div>
            <div class="textBlock">Текст 2</div>
            <div class="textBlock">Текст 3</div>
        </div>
        <div id="block2"></div>
    </div>
</body>

Как видите, на странице размещено два контейнера (block1 и block2). В первом находятся три блока с различным текстом. Второй контейнер пуст, в него можно будет перетягивать блоки.

Прежде всего, сделаем блоки «перетягиваемыми». Для этого нужно установить для соответствующего тега атрибут draggable="true" и назначить обработчик события dragstart.

Например (используется библиотека jQuery)

$('.textBlock')
    .attr('draggable', 'true')
    .bind('dragstart', function(event) {
        event.originalEvent.dataTransfer.setData('text/plain', $(this).html());
        return true;
    });

Кроме установки атрибута и обработчика необходимо сохранить данные, которые мы перетягиваем в объекте dataTransfer. Доступ к нему можно получить через объект event, который передаётся в первом параметре обработчика.

Для сохранения данных используется метод setData, в первом параметре которого нужно указать формат данных, а во втором – сами данные. К сожалению, как показала практика, разные браузеры поддерживают разные форматы. В стандарте речь идет только о двух: text/plain и text/uri-list. Firefox поддерживает шесть. В общем, чтобы пример нормально работал и в Firefox и в Chrome, я остановился на text/plain.

Теперь нужно подготовить контейнер к приёму объектов.

Для этого необходимо назначить ему обработчики событий dragenter, dragleave, dragover и drop. Причём первые три должны возвращать false, чтобы заблокировать стандартное поведение браузера.

В результате у меня получился следующий код.

$('#block2')
	.bind('dragenter', function(event) {
		$(this).addClass('dropHere');
		return false;
	})
	.bind('dragleave', function(event) {
		$(this).removeClass('dropHere');
		return false;
	})
	.bind('dragover', function(event) {
		return false;
	})
	.bind('drop', function(event) {
		$(this).removeClass('dropHere');
		var data = event.originalEvent.dataTransfer.getData('text/plain');
		$(this).append($('<div class="textBlock">' + data + '</div>'));
		return true;
	});

В обработчиках событий dragenter и dragleave выполняется установка и снятие CSS класса, который подсвечивает блок, когда над ним находится перетаскиваемый объект.

Событие drop возникает, когда пользователь отпускает левую клавишу мыши. При этом объект, который мы перетаскиваем, сам по себе не вставится. Но мы можем получить доступ к данным, которые были сохранены в dataTransfer. Для этого используется метод getData и в его параметре необходимо указать тип данных. После этого, с помощью append вставляем объект.

Как видите, принцип достаточно простой, и поддержка реализована неплохо. Например, работает перетаскивание из Chrome в Firefox и из Word в Firefox.

В общем, можно надеяться, что в будущем разработка сложных пользовательских интерфейсов станет немного проще, а пока есть множество хороших JS библиотек 😉