Вбудовані функції перетягування в HTML5 - HTML5 Rocks

  1. Вбудовані функції перетягування в HTML5
  2. Вступ
  3. виявлення функцій
  4. Створення перетягуваного змісту
  5. Прослуховування подій перетягування
  6. 1. Починайте перетягувати
  7. 2. dragenter, dragover і dragleave
  8. 3. Завершення перетягування
  9. об'єкт DataTransfer
  10. властивості перетягування
  11. перетягування файлів
  12. Перетягування з робочого столу в браузер
  13. Перетягування з браузера на робочий стіл
  14. приклади
  15. висновок
  16. посилання
  17. Вступ
  18. виявлення функцій
  19. Створення перетягуваного змісту
  20. Прослуховування подій перетягування
  21. 1. Починайте перетягувати
  22. 2. dragenter, dragover і dragleave
  23. 3. Завершення перетягування
  24. об'єкт DataTransfer
  25. властивості перетягування
  26. перетягування файлів
  27. Перетягування з робочого столу в браузер
  28. Перетягування з браузера на робочий стіл
  29. приклади
  30. висновок
  31. посилання
  32. Вступ
  33. виявлення функцій
  34. Створення перетягуваного змісту
  35. Прослуховування подій перетягування
  36. 1. Починайте перетягувати
  37. 2. dragenter, dragover і dragleave
  38. 3. Завершення перетягування
  39. об'єкт DataTransfer
  40. властивості перетягування
  41. перетягування файлів
  42. Перетягування з робочого столу в браузер
  43. Перетягування з браузера на робочий стіл
  44. приклади
  45. висновок

Вбудовані функції перетягування в HTML5

Вступ

Вже багато років ми використовуємо для спрощення складних елементів інтерфейсу, таких як анімації, закруглені кути і перетягування, бібліотеки JQuery і Dojo. Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?

перетягування (Drag and drop, DnD) - одна з найважливіших функцій в HTML5. Ця специфікація визначає подієвий механізм, API JavaScript і додаткову мітку, яка показує, що всі елементи на сторінці можуть перетягувати. Навряд чи хтось буде заперечувати проти вбудовування в браузер додаткових функцій. Реалізована в браузері функція перетягування означає більш швидкі і керовані веб-додатки.

виявлення функцій

Багато додатків, в яких використовується перетягування, не можуть без нього обходитися. Уявіть собі, що вам довелося б продумувати шахову партію, не маючи можливості переміщати фігури. Незважаючи на повну підтримку браузера, визначати, реалізовано чи в ньому перетягування (чи інша функція HTML5, що виконує ті ж завдання), потрібно для того, щоб забезпечити рішення, здатне якісно зменшувати потужність. Якщо функція перетягування недоступна, роботу програми можна реалізувати, підключивши бібліотеку.

Якщо вам необхідні можливості API, замість визначення параметра User-Agent браузера використовуйте виявлення функцій. Одна з кращих бібліотек для виявлення функцій називається Modernizr . Для кожної перевіряється функції Modernizr задає логічне значення. В результаті виходить дуже короткий код перевірки на наявність функції перетягування:

if (Modernizr.draganddrop) {// Browser supports HTML5 DnD. } Else {// Fallback to a library solution. }

Створення перетягуваного змісту

Зробити об'єкт перетягувати дуже легко: для цього використовується атрибут draggable = true. Перетягування можна включати практично для будь-яких елементів, в т. Ч. Зображень, посилань, файлів і навіть вузлів DOM.

Як приклад почнемо з створення перегруппіруемих стовпців. Базова позначка може виглядати приблизно так:

<Div id = "columns"> <div class = "column" draggable = "true"> <header> A </ header> </ div> <div class = "column" draggable = "true"> <header> B </ header> </ div> <div class = "column" draggable = "true"> <header> C </ header> </ div> </ div>

Слід зазначити, що в більшості браузерів перетягування виділених фрагментів тексту, зображень та елементів прив'язок з атрибутом href підтримується за замовчуванням. Наприклад, при перетягуванні логотипу на веб-сайті google.com виникає фантомне зображення:

Більшість браузерів підтримують перетягування зображень за замовчуванням.

Його можна перенести в адресний рядок, елемент <input type = "file" /> і навіть на робочий стіл. Щоб зробити перетягувати інші типи змісту, необхідно використовувати API перетягування HTML5.

За допомогою CSS3 можна уявити розмітку у вигляді стовпців. З додаванням атрибуту cursor: move користувачі отримують візуальний індикатор рухливості елемента:

<Style> / * Prevent the text contents of draggable elements from being selectable. * / [Draggable] {-moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; / * Required to make elements draggable in old WebKit * / -khtml-user-drag: element; -webkit-user-drag: element; } .Column {height: 150px; width: 150px; float: left; border: 2px solid # 666666; background-color: #ccc; margin-right: 5px; -webkit-border-radius: 10px; -ms-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: inset 0 0 3px # 000; -ms-box-shadow: inset 0 0 3px # 000; box-shadow: inset 0 0 3px # 000; text-align: center; cursor: move; } .Column header {color: #fff; text-shadow: # 000 0 1px; box-shadow: 5px; padding: 5px; background: -moz-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -webkit-gradient (linear, left top, right top, color-stop (0, rgb (0,0,0)), color-stop (0.50, rgb (79,79,79)), color-stop (1, rgb (21,21,21))); background: -webkit-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -ms-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); border-bottom: 1px solid #ddd; -webkit-border-top-left-radius: 10px; -moz-border-radius-topleft: 10px; -ms-border-radius-topleft: 10px; border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; -ms-border-top-right-radius: 10px; -moz-border-radius-topright: 10px; border-top-right-radius: 10px; } </ Style>

Результат (елементи можуть перетягувати, але нічого не роблять):

У наведеному вище прикладі більшість браузерів створюють фантомне зображення перетягуваного змісту. Інші (зокрема FF) в ході операції перетягування вимагають відправки даних . У наступному розділі ми зробимо приклад зі стовпцями більш цікавим, додавши прослуховувачі для обробки моделі подій перетягування.

Прослуховування подій перетягування

Для контролю над процесом перетягування можна використовувати цілий ряд подій:

  • dragstart
  • drag
  • dragenter
  • dragleave
  • dragover
  • drop
  • dragend

Для обробки алгоритму перетягування необхідно розуміти, де знаходяться вихідний елемент (звідки починається перетягування), корисні дані (що ми намагаємося перетягнути) і мета (область, в якій повинен виявитися об'єкт). Вихідним елементом може бути зображення, список, посилання, файловий об'єкт, блок HTML-коду, що завгодно. Мета - це зона (або кілька зон) перетягування, приймаюча дані, які користувач намагається перетягнути. Пам'ятайте про те, що не всі елементи можуть бути метою (наприклад, зображення).

1. Починайте перетягувати

Визначивши в змісті атрибути draggable = "true", додайте обробники подій dragstart, які будуть запускати послідовність перетягування для кожного стовпчика.

Як тільки користувач почне перетягувати стовпець, цей код зменшить його непрозорість до 40%:

function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false);});

результат:

Оскільки метою події dragstart є наш вихідний елемент, установка для атрибута this.style.opacity значення 40% дозволить користувачеві бачити переміщення обраного елемента. Нам залишилося тільки повернути 100-процентну непрозорість стовпців після перетягування. Для вирішення цього завдання використовується подія dragend. Детальніше ми розглянемо його пізніше.

2. dragenter, dragover і dragleave

Для створення додаткових візуальних підказок під час перетягування можна використовувати обробники подій dragenter, dragover і dragleave. Наприклад, якщо перетаскується виявляється на колонку, межа останнього стає пунктирною. Це покаже користувачам, що стовпці теж можуть бути метою перетягування.

<Style> .column.over {border: 2px dashed # 000; } </ Style> function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Function handleDragOver (e) {if (e.preventDefault) {e.preventDefault (); // Necessary. Allows us to drop. } E.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object. return false; } Function handleDragEnter (e) {// this / e.target is the current hover target. this.classList.add ( 'over'); } Function handleDragLeave (e) {this.classList.remove ( 'over'); // this / e.target is previous target element. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false); col.addEventListener ( 'dragover', handleDragOver, false); col.addEventListener ( 'dragleave', handleDragLeave, false);});

У цьому коді варто відзначити кілька моментів.

  • Атрибут this / e.target відрізняється для кожного типу подій і залежить від місця в моделі подій перетягування.
  • При перетягуванні такого об'єкта, як посилання, необхідно перевизначити поведінку браузера за замовчуванням, т. Е. Перехід по ній. Для цього потрібно викликати функцію e.preventDefault () в подію dragover. Інший варіант - використовувати в тому ж обробнику значення false. Потреба в таких заходах залежить від конкретного браузера, але вони безумовно не завадять.
  • Для перемикання класу over використовується подія dragenter, а не dragover Якщо використовувати dragover, наш клас CSS буде переключатися занадто часто, оскільки подія dragover спрацьовує при кожному наведенні на стовпець. В результаті оброблювачу браузера доведеться виконувати дуже багато зайвої роботи. Чим менше перерісовок, тим краще.

3. Завершення перетягування

Для обробки самого перетягування додайте прослуховувач для подій drop і dragend. У цьому обробнику необхідно перевизначити поведінку браузера за замовчуванням для переносів (зазвичай це щось на зразок переадресації). Заборонити події засмічувати модель DOM можна за допомогою функції e.stopPropagation ().

Наш приклад зі стовпцями не обійдеться без події drop, але спочатку необхідно дещо допрацювати, видаливши клас over з кожного стовпчика за допомогою події dragend:

... function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // stops the browser from redirecting. } // See the section on the DataTransfer object. return false; } Function handleDragEnd (e) {// this / e.target is the source node. [] .ForEach.call (cols, function (col) {col.classList.remove ( 'over');}); } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false) col.addEventListener ( 'dragover', handleDragOver, false ); col.addEventListener ( 'dragleave', handleDragLeave, false); col.addEventListener ( 'drop', handleDrop, false); col.addEventListener ( 'dragend', handleDragEnd, false);});

результат:

Якщо ви ретельно стежили за тим, що відбувається, то помітили, що перетягування стовпців в нашому прикладі як і раніше не працює так, як потрібно. Введемо об'єкт DataTransfer.

об'єкт DataTransfer

Властивість DataTransfer - це те саме місце, де реалізується перетягування. Воно містить частину даних, що відправляються після виконання цієї дії. Об'єкт dataTransfer встановлюється в подію dragstart, а зчитується і обробляється в подію drop. При виконанні функції e.dataTransfer.setData (format, data) змістом об'єкта призначається MIME-тип, а корисні дані передаються в якості аргументів.

У нашому прикладі в якості корисних даних виступає фактичний HTML-код вихідного стовпця:

var dragSrcEl = null; function handleDragStart (e) {// Target (this) element is the source node. this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData ( 'text / html', this.innerHTML); }

Зручно, що в об'єкта dataTransfer є також функція getData (format), що дозволяє доставляти перетягуються дані по MIME-типу. Ось як виглядає змінений процес перетягування стовпці:

function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // Stops some browsers from redirecting. } // Do not do anything if dropping the same column we're dragging. if (dragSrcEl! = this) {// Set the source column's HTML to the HTML of the columnwe dropped on. dragSrcEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData ( 'text / html'); } Return false; }

Для зручності при переміщенні стовпців я додав глобальну змінну dragSrcEl. У функції handleDragStart () в ній зберігається елемент innerHTML вихідного стовпця. Згодом його зчитує функція handleDrop (), міняючи місцями HTML-код вихідного і цільового стовпців.

результат:

властивості перетягування

Об'єкт dataTransfer має властивості, які створюють візуальну підказку для користувачів в процесі перетягування. Їх також можна використовувати для управління реакцією кожної мети перетягування на певний тип даних.

dataTransfer.effectAllowed Обмежує "тип перетягування", яке користувач може виконувати з елементом. Ця властивість використовується в моделі обробки перетягування для ініціалізації об'єкта dropEffect під час подій dragenter і dragover. Це властивості може набувати таких значень: none, copy, copyLink, copyMove, link, linkMove, move, all і uninitialized. dataTransfer.dropEffect Управляє реакцією, яку користувач отримує під час подій dragenter і dragover. Коли перетаскується наводиться на цільової елемент, покажчик браузера набирає вигляду, що відповідає типу передбачуваної операції (наприклад, копіювання, перенесення і т. Д.). Властивість може набувати таких значень: none, copy, link, move. e.dataTransfer.setDragImage (img element, x, y) Замість використання "фантомного зображення", яке браузер створює за замовчуванням, можна задати значок перетягування. var dragIcon = document.createElement ( 'img'); dragIcon.src = 'logo.png'; dragIcon.width = 100; e.dataTransfer.setDragImage (dragIcon, -10, -10);

Результат (при перетягуванні цих стовпців повинен відображатися логотип Google):

перетягування файлів

За допомогою API перетягування можна перетягувати файли з робочого столу в веб-додаток, відкрите у вікні браузера. Крім того, Google Chrome дозволяє перетягувати файлові об'єкти з вікна браузера на робочий стіл.

Перетягування з робочого столу в браузер

Перетягування файлу з робочого столу виконується за допомогою подій перетягування, як і для інших типів змісту. Основна відмінність полягає в обробнику події drop. Замість використання об'єкта dataTransfer.getData () для доступу до файлів дані містяться в властивість dataTransfer.files:

function handleDrop (e) {e.stopPropagation (); // Stops some browsers from redirecting. e.preventDefault (); var files = e.dataTransfer.files; for (var i = 0, f; f = files [i]; i ++) {// Read the File objects in this FileList. }}

Повне керівництво з перетягування файлів з робочого столу в браузер приведено в розділі Перетягування як спосіб вибору статті Читання локальних файлів в JavaScript .

Перетягування з браузера на робочий стіл

Повне керівництво з перетягування файлів з браузера на робочий стіл приведено в статті Перетягування файлів як з Gmail на веб-сайті CSS Ninja.

приклади

Ось кінцевий варіант з поліпшеним зовнішнім виглядом і лічильником переміщень:

У цьому прикладі за допомогою стовпців цікаво те, що кожен з них є одночасно вихідним об'єктом і метою перетягування. Найчастіше вихідний і цільовий елементи розрізняються. Подивіться приклад: html5demos.com/drag .

висновок

Модель перетягування в HTML5 складніше, ніж в інших рішеннях, таких як інтерфейс JQuery. Однак якщо у вас є можливість задіяти вбудований API браузера, її потрібно використовувати. Зрештою, в цьому і полягає суть HTML5: стандартизувати і зробити доступним весь набір власних можливостей браузера. Сподіваємося, що з часом в популярні бібліотеки, в яких використовується функція перетягування, буде включена підтримка HTML5 за замовчуванням і можливість по-різному налаштовувати JS-рішення.

посилання

Вбудовані функції перетягування в HTML5

Вступ

Вже багато років ми використовуємо для спрощення складних елементів інтерфейсу, таких як анімації, закруглені кути і перетягування, бібліотеки JQuery і Dojo. Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?

перетягування (Drag and drop, DnD) - одна з найважливіших функцій в HTML5. Ця специфікація визначає подієвий механізм, API JavaScript і додаткову мітку, яка показує, що всі елементи на сторінці можуть перетягувати. Навряд чи хтось буде заперечувати проти вбудовування в браузер додаткових функцій. Реалізована в браузері функція перетягування означає більш швидкі і керовані веб-додатки.

виявлення функцій

Багато додатків, в яких використовується перетягування, не можуть без нього обходитися. Уявіть собі, що вам довелося б продумувати шахову партію, не маючи можливості переміщати фігури. Незважаючи на повну підтримку браузера, визначати, реалізовано чи в ньому перетягування (чи інша функція HTML5, що виконує ті ж завдання), потрібно для того, щоб забезпечити рішення, здатне якісно зменшувати потужність. Якщо функція перетягування недоступна, роботу програми можна реалізувати, підключивши бібліотеку.

Якщо вам необхідні можливості API, замість визначення параметра User-Agent браузера використовуйте виявлення функцій. Одна з кращих бібліотек для виявлення функцій називається Modernizr . Для кожної перевіряється функції Modernizr задає логічне значення. В результаті виходить дуже короткий код перевірки на наявність функції перетягування:

if (Modernizr.draganddrop) {// Browser supports HTML5 DnD. } Else {// Fallback to a library solution. }

Створення перетягуваного змісту

Зробити об'єкт перетягувати дуже легко: для цього використовується атрибут draggable = true. Перетягування можна включати практично для будь-яких елементів, в т. Ч. Зображень, посилань, файлів і навіть вузлів DOM.

Як приклад почнемо з створення перегруппіруемих стовпців. Базова позначка може виглядати приблизно так:

<Div id = "columns"> <div class = "column" draggable = "true"> <header> A </ header> </ div> <div class = "column" draggable = "true"> <header> B </ header> </ div> <div class = "column" draggable = "true"> <header> C </ header> </ div> </ div>

Слід зазначити, що в більшості браузерів перетягування виділених фрагментів тексту, зображень та елементів прив'язок з атрибутом href підтримується за замовчуванням. Наприклад, при перетягуванні логотипу на веб-сайті google.com виникає фантомне зображення:

Більшість браузерів підтримують перетягування зображень за замовчуванням.

Його можна перенести в адресний рядок, елемент <input type = "file" /> і навіть на робочий стіл. Щоб зробити перетягувати інші типи змісту, необхідно використовувати API перетягування HTML5.

За допомогою CSS3 можна уявити розмітку у вигляді стовпців. З додаванням атрибуту cursor: move користувачі отримують візуальний індикатор рухливості елемента:

<Style> / * Prevent the text contents of draggable elements from being selectable. * / [Draggable] {-moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; / * Required to make elements draggable in old WebKit * / -khtml-user-drag: element; -webkit-user-drag: element; } .Column {height: 150px; width: 150px; float: left; border: 2px solid # 666666; background-color: #ccc; margin-right: 5px; -webkit-border-radius: 10px; -ms-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: inset 0 0 3px # 000; -ms-box-shadow: inset 0 0 3px # 000; box-shadow: inset 0 0 3px # 000; text-align: center; cursor: move; } .Column header {color: #fff; text-shadow: # 000 0 1px; box-shadow: 5px; padding: 5px; background: -moz-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -webkit-gradient (linear, left top, right top, color-stop (0, rgb (0,0,0)), color-stop (0.50, rgb (79,79,79)), color-stop (1, rgb (21,21,21))); background: -webkit-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -ms-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); border-bottom: 1px solid #ddd; -webkit-border-top-left-radius: 10px; -moz-border-radius-topleft: 10px; -ms-border-radius-topleft: 10px; border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; -ms-border-top-right-radius: 10px; -moz-border-radius-topright: 10px; border-top-right-radius: 10px; } </ Style>

Результат (елементи можуть перетягувати, але нічого не роблять):

У наведеному вище прикладі більшість браузерів створюють фантомне зображення перетягуваного змісту. Інші (зокрема FF) в ході операції перетягування вимагають відправки даних . У наступному розділі ми зробимо приклад зі стовпцями більш цікавим, додавши прослуховувачі для обробки моделі подій перетягування.

Прослуховування подій перетягування

Для контролю над процесом перетягування можна використовувати цілий ряд подій:

  • dragstart
  • drag
  • dragenter
  • dragleave
  • dragover
  • drop
  • dragend

Для обробки алгоритму перетягування необхідно розуміти, де знаходяться вихідний елемент (звідки починається перетягування), корисні дані (що ми намагаємося перетягнути) і мета (область, в якій повинен виявитися об'єкт). Вихідним елементом може бути зображення, список, посилання, файловий об'єкт, блок HTML-коду, що завгодно. Мета - це зона (або кілька зон) перетягування, приймаюча дані, які користувач намагається перетягнути. Пам'ятайте про те, що не всі елементи можуть бути метою (наприклад, зображення).

1. Починайте перетягувати

Визначивши в змісті атрибути draggable = "true", додайте обробники подій dragstart, які будуть запускати послідовність перетягування для кожного стовпчика.

Як тільки користувач почне перетягувати стовпець, цей код зменшить його непрозорість до 40%:

function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false);});

результат:

Оскільки метою події dragstart є наш вихідний елемент, установка для атрибута this.style.opacity значення 40% дозволить користувачеві бачити переміщення обраного елемента. Нам залишилося тільки повернути 100-процентну непрозорість стовпців після перетягування. Для вирішення цього завдання використовується подія dragend. Детальніше ми розглянемо його пізніше.

2. dragenter, dragover і dragleave

Для створення додаткових візуальних підказок під час перетягування можна використовувати обробники подій dragenter, dragover і dragleave. Наприклад, якщо перетаскується виявляється на колонку, межа останнього стає пунктирною. Це покаже користувачам, що стовпці теж можуть бути метою перетягування.

<Style> .column.over {border: 2px dashed # 000; } </ Style> function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Function handleDragOver (e) {if (e.preventDefault) {e.preventDefault (); // Necessary. Allows us to drop. } E.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object. return false; } Function handleDragEnter (e) {// this / e.target is the current hover target. this.classList.add ( 'over'); } Function handleDragLeave (e) {this.classList.remove ( 'over'); // this / e.target is previous target element. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false); col.addEventListener ( 'dragover', handleDragOver, false); col.addEventListener ( 'dragleave', handleDragLeave, false);});

У цьому коді варто відзначити кілька моментів.

  • Атрибут this / e.target відрізняється для кожного типу подій і залежить від місця в моделі подій перетягування.
  • При перетягуванні такого об'єкта, як посилання, необхідно перевизначити поведінку браузера за замовчуванням, т. Е. Перехід по ній. Для цього потрібно викликати функцію e.preventDefault () в подію dragover. Інший варіант - використовувати в тому ж обробнику значення false. Потреба в таких заходах залежить від конкретного браузера, але вони безумовно не завадять.
  • Для перемикання класу over використовується подія dragenter, а не dragover Якщо використовувати dragover, наш клас CSS буде переключатися занадто часто, оскільки подія dragover спрацьовує при кожному наведенні на стовпець. В результаті оброблювачу браузера доведеться виконувати дуже багато зайвої роботи. Чим менше перерісовок, тим краще.

3. Завершення перетягування

Для обробки самого перетягування додайте прослуховувач для подій drop і dragend. У цьому обробнику необхідно перевизначити поведінку браузера за замовчуванням для переносів (зазвичай це щось на зразок переадресації). Заборонити події засмічувати модель DOM можна за допомогою функції e.stopPropagation ().

Наш приклад зі стовпцями не обійдеться без події drop, але спочатку необхідно дещо допрацювати, видаливши клас over з кожного стовпчика за допомогою події dragend:

... function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // stops the browser from redirecting. } // See the section on the DataTransfer object. return false; } Function handleDragEnd (e) {// this / e.target is the source node. [] .ForEach.call (cols, function (col) {col.classList.remove ( 'over');}); } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false) col.addEventListener ( 'dragover', handleDragOver, false ); col.addEventListener ( 'dragleave', handleDragLeave, false); col.addEventListener ( 'drop', handleDrop, false); col.addEventListener ( 'dragend', handleDragEnd, false);});

результат:

Якщо ви ретельно стежили за тим, що відбувається, то помітили, що перетягування стовпців в нашому прикладі як і раніше не працює так, як потрібно. Введемо об'єкт DataTransfer.

об'єкт DataTransfer

Властивість DataTransfer - це те саме місце, де реалізується перетягування. Воно містить частину даних, що відправляються після виконання цієї дії. Об'єкт dataTransfer встановлюється в подію dragstart, а зчитується і обробляється в подію drop. При виконанні функції e.dataTransfer.setData (format, data) змістом об'єкта призначається MIME-тип, а корисні дані передаються в якості аргументів.

У нашому прикладі в якості корисних даних виступає фактичний HTML-код вихідного стовпця:

var dragSrcEl = null; function handleDragStart (e) {// Target (this) element is the source node. this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData ( 'text / html', this.innerHTML); }

Зручно, що в об'єкта dataTransfer є також функція getData (format), що дозволяє доставляти перетягуються дані по MIME-типу. Ось як виглядає змінений процес перетягування стовпці:

function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // Stops some browsers from redirecting. } // Do not do anything if dropping the same column we're dragging. if (dragSrcEl! = this) {// Set the source column's HTML to the HTML of the columnwe dropped on. dragSrcEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData ( 'text / html'); } Return false; }

Для зручності при переміщенні стовпців я додав глобальну змінну dragSrcEl. У функції handleDragStart () в ній зберігається елемент innerHTML вихідного стовпця. Згодом його зчитує функція handleDrop (), міняючи місцями HTML-код вихідного і цільового стовпців.

результат:

властивості перетягування

Об'єкт dataTransfer має властивості, які створюють візуальну підказку для користувачів в процесі перетягування. Їх також можна використовувати для управління реакцією кожної мети перетягування на певний тип даних.

dataTransfer.effectAllowed Обмежує "тип перетягування", яке користувач може виконувати з елементом. Ця властивість використовується в моделі обробки перетягування для ініціалізації об'єкта dropEffect під час подій dragenter і dragover. Це властивості може набувати таких значень: none, copy, copyLink, copyMove, link, linkMove, move, all і uninitialized. dataTransfer.dropEffect Управляє реакцією, яку користувач отримує під час подій dragenter і dragover. Коли перетаскується наводиться на цільової елемент, покажчик браузера набирає вигляду, що відповідає типу передбачуваної операції (наприклад, копіювання, перенесення і т. Д.). Властивість може набувати таких значень: none, copy, link, move. e.dataTransfer.setDragImage (img element, x, y) Замість використання "фантомного зображення", яке браузер створює за замовчуванням, можна задати значок перетягування. var dragIcon = document.createElement ( 'img'); dragIcon.src = 'logo.png'; dragIcon.width = 100; e.dataTransfer.setDragImage (dragIcon, -10, -10);

Результат (при перетягуванні цих стовпців повинен відображатися логотип Google):

перетягування файлів

За допомогою API перетягування можна перетягувати файли з робочого столу в веб-додаток, відкрите у вікні браузера. Крім того, Google Chrome дозволяє перетягувати файлові об'єкти з вікна браузера на робочий стіл.

Перетягування з робочого столу в браузер

Перетягування файлу з робочого столу виконується за допомогою подій перетягування, як і для інших типів змісту. Основна відмінність полягає в обробнику події drop. Замість використання об'єкта dataTransfer.getData () для доступу до файлів дані містяться в властивість dataTransfer.files:

function handleDrop (e) {e.stopPropagation (); // Stops some browsers from redirecting. e.preventDefault (); var files = e.dataTransfer.files; for (var i = 0, f; f = files [i]; i ++) {// Read the File objects in this FileList. }}

Повне керівництво з перетягування файлів з робочого столу в браузер приведено в розділі Перетягування як спосіб вибору статті Читання локальних файлів в JavaScript .

Перетягування з браузера на робочий стіл

Повне керівництво з перетягування файлів з браузера на робочий стіл приведено в статті Перетягування файлів як з Gmail на веб-сайті CSS Ninja.

приклади

Ось кінцевий варіант з поліпшеним зовнішнім виглядом і лічильником переміщень:

У цьому прикладі за допомогою стовпців цікаво те, що кожен з них є одночасно вихідним об'єктом і метою перетягування. Найчастіше вихідний і цільовий елементи розрізняються. Подивіться приклад: html5demos.com/drag .

висновок

Модель перетягування в HTML5 складніше, ніж в інших рішеннях, таких як інтерфейс JQuery. Однак якщо у вас є можливість задіяти вбудований API браузера, її потрібно використовувати. Зрештою, в цьому і полягає суть HTML5: стандартизувати і зробити доступним весь набір власних можливостей браузера. Сподіваємося, що з часом в популярні бібліотеки, в яких використовується функція перетягування, буде включена підтримка HTML5 за замовчуванням і можливість по-різному налаштовувати JS-рішення.

посилання

Вбудовані функції перетягування в HTML5

Вступ

Вже багато років ми використовуємо для спрощення складних елементів інтерфейсу, таких як анімації, закруглені кути і перетягування, бібліотеки JQuery і Dojo. Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?

перетягування (Drag and drop, DnD) - одна з найважливіших функцій в HTML5. Ця специфікація визначає подієвий механізм, API JavaScript і додаткову мітку, яка показує, що всі елементи на сторінці можуть перетягувати. Навряд чи хтось буде заперечувати проти вбудовування в браузер додаткових функцій. Реалізована в браузері функція перетягування означає більш швидкі і керовані веб-додатки.

виявлення функцій

Багато додатків, в яких використовується перетягування, не можуть без нього обходитися. Уявіть собі, що вам довелося б продумувати шахову партію, не маючи можливості переміщати фігури. Незважаючи на повну підтримку браузера, визначати, реалізовано чи в ньому перетягування (чи інша функція HTML5, що виконує ті ж завдання), потрібно для того, щоб забезпечити рішення, здатне якісно зменшувати потужність. Якщо функція перетягування недоступна, роботу програми можна реалізувати, підключивши бібліотеку.

Якщо вам необхідні можливості API, замість визначення параметра User-Agent браузера використовуйте виявлення функцій. Одна з кращих бібліотек для виявлення функцій називається Modernizr . Для кожної перевіряється функції Modernizr задає логічне значення. В результаті виходить дуже короткий код перевірки на наявність функції перетягування:

if (Modernizr.draganddrop) {// Browser supports HTML5 DnD. } Else {// Fallback to a library solution. }

Створення перетягуваного змісту

Зробити об'єкт перетягувати дуже легко: для цього використовується атрибут draggable = true. Перетягування можна включати практично для будь-яких елементів, в т. Ч. Зображень, посилань, файлів і навіть вузлів DOM.

Як приклад почнемо з створення перегруппіруемих стовпців. Базова позначка може виглядати приблизно так:

<Div id = "columns"> <div class = "column" draggable = "true"> <header> A </ header> </ div> <div class = "column" draggable = "true"> <header> B </ header> </ div> <div class = "column" draggable = "true"> <header> C </ header> </ div> </ div>

Слід зазначити, що в більшості браузерів перетягування виділених фрагментів тексту, зображень та елементів прив'язок з атрибутом href підтримується за замовчуванням. Наприклад, при перетягуванні логотипу на веб-сайті google.com виникає фантомне зображення:

Більшість браузерів підтримують перетягування зображень за замовчуванням.

Його можна перенести в адресний рядок, елемент <input type = "file" /> і навіть на робочий стіл. Щоб зробити перетягувати інші типи змісту, необхідно використовувати API перетягування HTML5.

За допомогою CSS3 можна уявити розмітку у вигляді стовпців. З додаванням атрибуту cursor: move користувачі отримують візуальний індикатор рухливості елемента:

<Style> / * Prevent the text contents of draggable elements from being selectable. * / [Draggable] {-moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; / * Required to make elements draggable in old WebKit * / -khtml-user-drag: element; -webkit-user-drag: element; } .Column {height: 150px; width: 150px; float: left; border: 2px solid # 666666; background-color: #ccc; margin-right: 5px; -webkit-border-radius: 10px; -ms-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; -webkit-box-shadow: inset 0 0 3px # 000; -ms-box-shadow: inset 0 0 3px # 000; box-shadow: inset 0 0 3px # 000; text-align: center; cursor: move; } .Column header {color: #fff; text-shadow: # 000 0 1px; box-shadow: 5px; padding: 5px; background: -moz-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -webkit-gradient (linear, left top, right top, color-stop (0, rgb (0,0,0)), color-stop (0.50, rgb (79,79,79)), color-stop (1, rgb (21,21,21))); background: -webkit-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); background: -ms-linear-gradient (left center, rgb (0,0,0), rgb (79,79,79), rgb (21,21,21)); border-bottom: 1px solid #ddd; -webkit-border-top-left-radius: 10px; -moz-border-radius-topleft: 10px; -ms-border-radius-topleft: 10px; border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; -ms-border-top-right-radius: 10px; -moz-border-radius-topright: 10px; border-top-right-radius: 10px; } </ Style>

Результат (елементи можуть перетягувати, але нічого не роблять):

У наведеному вище прикладі більшість браузерів створюють фантомне зображення перетягуваного змісту. Інші (зокрема FF) в ході операції перетягування вимагають відправки даних . У наступному розділі ми зробимо приклад зі стовпцями більш цікавим, додавши прослуховувачі для обробки моделі подій перетягування.

Прослуховування подій перетягування

Для контролю над процесом перетягування можна використовувати цілий ряд подій:

  • dragstart
  • drag
  • dragenter
  • dragleave
  • dragover
  • drop
  • dragend

Для обробки алгоритму перетягування необхідно розуміти, де знаходяться вихідний елемент (звідки починається перетягування), корисні дані (що ми намагаємося перетягнути) і мета (область, в якій повинен виявитися об'єкт). Вихідним елементом може бути зображення, список, посилання, файловий об'єкт, блок HTML-коду, що завгодно. Мета - це зона (або кілька зон) перетягування, приймаюча дані, які користувач намагається перетягнути. Пам'ятайте про те, що не всі елементи можуть бути метою (наприклад, зображення).

1. Починайте перетягувати

Визначивши в змісті атрибути draggable = "true", додайте обробники подій dragstart, які будуть запускати послідовність перетягування для кожного стовпчика.

Як тільки користувач почне перетягувати стовпець, цей код зменшить його непрозорість до 40%:

function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false);});

результат:

Оскільки метою події dragstart є наш вихідний елемент, установка для атрибута this.style.opacity значення 40% дозволить користувачеві бачити переміщення обраного елемента. Нам залишилося тільки повернути 100-процентну непрозорість стовпців після перетягування. Для вирішення цього завдання використовується подія dragend. Детальніше ми розглянемо його пізніше.

2. dragenter, dragover і dragleave

Для створення додаткових візуальних підказок під час перетягування можна використовувати обробники подій dragenter, dragover і dragleave. Наприклад, якщо перетаскується виявляється на колонку, межа останнього стає пунктирною. Це покаже користувачам, що стовпці теж можуть бути метою перетягування.

<Style> .column.over {border: 2px dashed # 000; } </ Style> function handleDragStart (e) {this.style.opacity = '0.4'; // this / e.target is the source node. } Function handleDragOver (e) {if (e.preventDefault) {e.preventDefault (); // Necessary. Allows us to drop. } E.dataTransfer.dropEffect = 'move'; // See the section on the DataTransfer object. return false; } Function handleDragEnter (e) {// this / e.target is the current hover target. this.classList.add ( 'over'); } Function handleDragLeave (e) {this.classList.remove ( 'over'); // this / e.target is previous target element. } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false); col.addEventListener ( 'dragover', handleDragOver, false); col.addEventListener ( 'dragleave', handleDragLeave, false);});

У цьому коді варто відзначити кілька моментів.

  • Атрибут this / e.target відрізняється для кожного типу подій і залежить від місця в моделі подій перетягування.
  • При перетягуванні такого об'єкта, як посилання, необхідно перевизначити поведінку браузера за замовчуванням, т. Е. Перехід по ній. Для цього потрібно викликати функцію e.preventDefault () в подію dragover. Інший варіант - використовувати в тому ж обробнику значення false. Потреба в таких заходах залежить від конкретного браузера, але вони безумовно не завадять.
  • Для перемикання класу over використовується подія dragenter, а не dragover Якщо використовувати dragover, наш клас CSS буде переключатися занадто часто, оскільки подія dragover спрацьовує при кожному наведенні на стовпець. В результаті оброблювачу браузера доведеться виконувати дуже багато зайвої роботи. Чим менше перерісовок, тим краще.

3. Завершення перетягування

Для обробки самого перетягування додайте прослуховувач для подій drop і dragend. У цьому обробнику необхідно перевизначити поведінку браузера за замовчуванням для переносів (зазвичай це щось на зразок переадресації). Заборонити події засмічувати модель DOM можна за допомогою функції e.stopPropagation ().

Наш приклад зі стовпцями не обійдеться без події drop, але спочатку необхідно дещо допрацювати, видаливши клас over з кожного стовпчика за допомогою події dragend:

... function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // stops the browser from redirecting. } // See the section on the DataTransfer object. return false; } Function handleDragEnd (e) {// this / e.target is the source node. [] .ForEach.call (cols, function (col) {col.classList.remove ( 'over');}); } Var cols = document.querySelectorAll ( '# columns .column'); [] .ForEach.call (cols, function (col) {col.addEventListener ( 'dragstart', handleDragStart, false); col.addEventListener ( 'dragenter', handleDragEnter, false) col.addEventListener ( 'dragover', handleDragOver, false ); col.addEventListener ( 'dragleave', handleDragLeave, false); col.addEventListener ( 'drop', handleDrop, false); col.addEventListener ( 'dragend', handleDragEnd, false);});

результат:

Якщо ви ретельно стежили за тим, що відбувається, то помітили, що перетягування стовпців в нашому прикладі як і раніше не працює так, як потрібно. Введемо об'єкт DataTransfer.

об'єкт DataTransfer

Властивість DataTransfer - це те саме місце, де реалізується перетягування. Воно містить частину даних, що відправляються після виконання цієї дії. Об'єкт dataTransfer встановлюється в подію dragstart, а зчитується і обробляється в подію drop. При виконанні функції e.dataTransfer.setData (format, data) змістом об'єкта призначається MIME-тип, а корисні дані передаються в якості аргументів.

У нашому прикладі в якості корисних даних виступає фактичний HTML-код вихідного стовпця:

var dragSrcEl = null; function handleDragStart (e) {// Target (this) element is the source node. this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData ( 'text / html', this.innerHTML); }

Зручно, що в об'єкта dataTransfer є також функція getData (format), що дозволяє доставляти перетягуються дані по MIME-типу. Ось як виглядає змінений процес перетягування стовпці:

function handleDrop (e) {// this / e.target is current target element. if (e.stopPropagation) {e.stopPropagation (); // Stops some browsers from redirecting. } // Do not do anything if dropping the same column we're dragging. if (dragSrcEl! = this) {// Set the source column's HTML to the HTML of the columnwe dropped on. dragSrcEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData ( 'text / html'); } Return false; }

Для зручності при переміщенні стовпців я додав глобальну змінну dragSrcEl. У функції handleDragStart () в ній зберігається елемент innerHTML вихідного стовпця. Згодом його зчитує функція handleDrop (), міняючи місцями HTML-код вихідного і цільового стовпців.

результат:

властивості перетягування

Об'єкт dataTransfer має властивості, які створюють візуальну підказку для користувачів в процесі перетягування. Їх також можна використовувати для управління реакцією кожної мети перетягування на певний тип даних.

dataTransfer.effectAllowed Обмежує "тип перетягування", яке користувач може виконувати з елементом. Ця властивість використовується в моделі обробки перетягування для ініціалізації об'єкта dropEffect під час подій dragenter і dragover. Це властивості може набувати таких значень: none, copy, copyLink, copyMove, link, linkMove, move, all і uninitialized. dataTransfer.dropEffect Управляє реакцією, яку користувач отримує під час подій dragenter і dragover. Коли перетаскується наводиться на цільової елемент, покажчик браузера набирає вигляду, що відповідає типу передбачуваної операції (наприклад, копіювання, перенесення і т. Д.). Властивість може набувати таких значень: none, copy, link, move. e.dataTransfer.setDragImage (img element, x, y) Замість використання "фантомного зображення", яке браузер створює за замовчуванням, можна задати значок перетягування. var dragIcon = document.createElement ( 'img'); dragIcon.src = 'logo.png'; dragIcon.width = 100; e.dataTransfer.setDragImage (dragIcon, -10, -10);

Результат (при перетягуванні цих стовпців повинен відображатися логотип Google):

перетягування файлів

За допомогою API перетягування можна перетягувати файли з робочого столу в веб-додаток, відкрите у вікні браузера. Крім того, Google Chrome дозволяє перетягувати файлові об'єкти з вікна браузера на робочий стіл.

Перетягування з робочого столу в браузер

Перетягування файлу з робочого столу виконується за допомогою подій перетягування, як і для інших типів змісту. Основна відмінність полягає в обробнику події drop. Замість використання об'єкта dataTransfer.getData () для доступу до файлів дані містяться в властивість dataTransfer.files:

function handleDrop (e) {e.stopPropagation (); // Stops some browsers from redirecting. e.preventDefault (); var files = e.dataTransfer.files; for (var i = 0, f; f = files [i]; i ++) {// Read the File objects in this FileList. }}

Повне керівництво з перетягування файлів з робочого столу в браузер приведено в розділі Перетягування як спосіб вибору статті Читання локальних файлів в JavaScript .

Перетягування з браузера на робочий стіл

Повне керівництво з перетягування файлів з браузера на робочий стіл приведено в статті Перетягування файлів як з Gmail на веб-сайті CSS Ninja.

приклади

Ось кінцевий варіант з поліпшеним зовнішнім виглядом і лічильником переміщень:

У цьому прикладі за допомогою стовпців цікаво те, що кожен з них є одночасно вихідним об'єктом і метою перетягування. Найчастіше вихідний і цільовий елементи розрізняються. Подивіться приклад: html5demos.com/drag .

висновок

Модель перетягування в HTML5 складніше, ніж в інших рішеннях, таких як інтерфейс JQuery. Однак якщо у вас є можливість задіяти вбудований API браузера, її потрібно використовувати. Зрештою, в цьому і полягає суть HTML5: стандартизувати і зробити доступним весь набір власних можливостей браузера. Сподіваємося, що з часом в популярні бібліотеки, в яких використовується функція перетягування, буде включена підтримка HTML5 за замовчуванням і можливість по-різному налаштовувати JS-рішення.

посилання

Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?
Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?
Безсумнівно, зовнішня привабливість важлива для створення якісних веб-сайтів, але навіщо потрібна бібліотека для загальних завдань, які використовують всі розробники?