Přejít k navigační liště

Zdroják » JavaScript » Webdesignérův průvodce po HTML5: Táhni a srůstej

Webdesignérův průvodce po HTML5: Táhni a srůstej

Čtenář jistě promine kulturní narážku v nadpisu. Samosebou jde o implementaci metody drag-and-drop, tedy česky „táhni a pusť“. Podpora pro tuto metodu je totiž zahrnuta již do specifikace HTML5, takže už není potřeba k těmto účelům využívat JavaScriptových knihoven (i když se JavaScriptu nevyhneme).

Technika drag-n-drop (Drag&Drop, táhni a pusť) je jednou ze základních metod práce s objekty v grafických UI, kdy pomocí vstupního zařízení je objekt „uchopen“, pak „přenesen“ na jiné místo a tam „položen“ či „vložen“, dle kontextu. Není divu, že webové aplikace mají potřebu tuto techniku implementovat taky, a specifikace HTML5 jim v tomto vychází vstříc.

Základy

Pokud chceme něco táhnout a pustit, musíme mít ve stránce dva elementy:

  1. ten, který se bude přesouvat (draggable)
  2. ten, nad kterým bude element puštěn (container)

Netřeba v tom hledat žádné složitosti – jak tažený objekt, tak kontejner může být obyčejný div.

Draggable

Elementy, které budou přetahovány, musí mít nastavený atribut draggable na hodnotu true. Zde poznámka: Při testech nestačilo pouhé uvedení atributu (jak umožňuje HTML) ani nastavení např. na hodnotu 1 či „on“, bylo třeba zapsat „draggable=true“. Pokud má element nastaven draggable atribut, bude možné jej uchopit a táhnout. Bez něho se bude při podobném pokusu zvýrazňovat text.

<div id=draggable1 draggable=true>Prvek 1</div>

Elementy, které lze přetahovat, budou vyvolávat i události, konkrétně dragstart a dragend.

dragstart

Událost „dragstart“ je vyvolána ve chvíli, kdy uživatel zahájí tažení objektu. V obsluze této události se nejčastěji nastavuje obsah („náklad“, dataTransfer) daného elementu, může se nastavit i „zástupce“, který bude zobrazen během přetahování a nastavují se např. i povolené operace (kopírování, přesun, vytvoření odkazu…) Obsluha události může celou operaci zrušit, pokud vrátí hodnotu false.

dragend

Pokud skončí tažení, ať už puštěním nebo zrušením, je vyvolána událost dragend. Obsluha by měla uklidit (odstranit dataTransfer).

Container

Kontejner, tedy oblast, do níž jsou přetahované objekty „vhazovány“, nemusí mít žádný speciální atribut (před krátkým časem se v návrhu spcifikace objevil atribut „dropzone“, ale je ve stádiu „first draw“). Stačí pouze řádně obsloužit příslušné události.

dragenter

Událost je vyvolána, pokud uživatel přetáhne objekt nad aktuální element. Není nutné ji implementovat.

dragover

Událost je vyvolávána, dokud se objekt pohybuje nad elementem. Pokud obsluha vrací true, prohlížeč naznačí uživateli, že zde nelze objekt upustit. Pokud obslužná rutina vrátí false, lze objekt pustit. V obsluze této metody je možné nastavit např. způsob přetažení (copy / move / link) apod.

drop

Ukončuje celou operaci přetažení. V obsluze této události je potřeba zpracovat celou operaci a udělat potřebné (přesunout objekt na nové místo, vyvolat akci apod.)

Posloupnost událostí při úspěšné operaci přetažení je následující:

  1. dragstart @ draggable
  2. dragenter @ container
  3. dragover @ container
  4. drop @ container
  5. dragend @ draggable

Ukázka

Ukažme si jednoduché demo. Začneme vytvořením tří oblastí:

<!DOCTYPE html>
<meta charset=utf-8>
<html>
  <head>
    <title>Drag'n'Drop Demo</title>
  </head>
  <body>
    <h1>Drag'n'Drop Demo</h1>
    <div id=container1 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Zásobník</h2>   
    </div>
   
    <div id=container2 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Sudá</h2>
    </div>
    <div id=container3 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Lichá</h2>
    </div>
   
    <div id=container>
      <h2>Konzole</h2>
      <textarea id=log></textarea>
    </div>
  </body>
</html>

Vytvořili jsme si tři oblasti – kontejnery (plus jednu testovací, kde se bude vypisovat log). Do první oblasti („zásobníku“) si umístíme objekty, které budeme přetahovat:

    <div id=container1 ondragover="return over(event)" ondrop="return drop(event)">
      <h2>Zásobník</h2>
   
      <div id=draggable1 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 1</div>
      <div id=draggable2 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 2</div>
      <div id=draggable3 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 3</div>
      <div id=draggable4 draggable=true ondragstart="return start(event)" ondragend="return end(event)">Prvek 4</div>
   
    </div>

Objekty mají nastavenou obsluhu událostí dragstart i dragend  a mají atribut  draggable.

Než se dostaneme k vlastnímu oživení, tak si elementy trošku nastylujme:

    <style>
      #container1, #container2, #container3, #container {
        float:left; width:250px; height:550px;
        padding:10px; margin:10px;
        background-color: #cff;}
      #draggable1, #draggable2, #draggable3, #draggable4, #draggable {
        width:75px; height:70px; padding:5px;
        margin:5px;background-color: #ffc;}
      #log {width:230px;height:400px;}
    </style>

Obsluha událostí

Aby dávalo přetahování nějaký smysl, je třeba nastavit obsluhu patřičných událostí. My si v příkladu ukážeme i využití objektu dataTransfer, pomocí něhož můžeme dát přetahovanému elementu nějaký „vnitřní“ obsah – můžeme nastavit jeho reprezentaci v různých formátech, podobně jako např. u systémové schránky.

Ondragstart

      function start(e) {
        e.dataTransfer.effectAllowed='all';
        e.dataTransfer.setData("text/plain", e.target.getAttribute('id'));
        e.dataTransfer.setDragImage(e.target, 10, 50);
        return true;
      }

První řádek obsluhy události říká, že přetahovaný objekt lze kopírovat, přesouvat i vytvářet zástupce ( effectAllowed='all'). Druhý řádek nastavuje reprezentaci objektu pro kontejnery, které jsou schopné přijmout prostý text (text/plain). Hodnota bude rovna id příslušného elementu. Pokud si tedy objekt přetáhneme do textarea (nebo třeba do textového editoru), získáme řetězec, např. „draggable1“. Analogicky bychom mohli nastavit obsah pro „text/html“, a ten by byl použit tam, kde lze vkládat HTML (rich text editory apod.) či jakýkoli jiný typ obsahu (obrázek, soubor, URL, …)

Třetí řádek nastavuje „obrázek“, který bude symbolizovat objekt během tažení. Zde je to objekt sám. Jak vidíte, lze nastavit i bod, v němž bude kurzor (to jsou ty dvě čísla).

Vracíme true, operace přetahování je povolena.

Ondragend

      function end(e) {
        e.dataTransfer.clearData("text/plain");
        return true;
      }

Po skončení přesunu uklidíme – tedy smažeme obsah v objektu dataTransfer a vrátíme true – vše dopadlo dobře. Ve Firefoxu to bohužel nedopadne dobře – vrátí chybu, protože ve FF nelze s objektem dataTransfer manipulovat jinde než v ondragstart.

Ondragover

      function over(e) {
        var iddraggable = e.dataTransfer.getData("text/plain");
        var id = e.target.getAttribute('id');
        if (id =='container1') {e.preventDefault();return false;}
        if(id =='container2' && (iddraggable == 'draggable2' || iddraggable == 'draggable4'))
          {e.preventDefault();return false;}
          else if (id =='container3' && (iddraggable == 'draggable1' || iddraggable =='draggable3'))
            {e.preventDefault();return false;}
            else return true;
      }

Obsluha události dragover je vyvolávána, jak jsme si řekli, po dobu co se objekt pohybuje nad kontejnerem. Identifikátor taženého objektu zjistíme z textové reprezentace (viz výše, uložili jsme si jej tam v dragstart). Identifikátor kontejneru zjistíme z cíle události ( event.target).

Pomocí jednoduchých pravidel pak rozhodneme o tom, zda povolíme puštění. Nad kontejnerem 1 přijmeme vše, takže jen vrátíme false (zde false znamená, že je možno pustit, viz výše!) Nad kontejnerem 2 přijmeme jen objekty 2 a 4, nad trojkou jen 1 a 3 (čistě jako ukázku možností, nemá to žádný hlubší význam). Tam, kde je povoleno puštění objektu, vrátíme false, jinak true. Pro jistotu ještě zabráníme vyvolání výchozí obsluhy (mělo by stačit prosté return false, ale podle některých uživatelů jsou prohlížeče, v nichž to nestačí).

Ondrop

      function drop(e) {
        e.stopPropagation();
        e.preventDefault();
        var iddraggable = e.dataTransfer.getData("text/plain");
        e.target.appendChild (document.getElementById(iddraggable));
        return false;
      }

Puštění objektu nejprve zabrání vyvolání výchozí obsluze událostí. Zjistíme si ID přetaženého elementu (máme ho v dataTransfer) a daný element přesuneme do cílové oblasti.

V ukázce je v rámci obsluhy události drop ještě výpis objektu dataTransfer do logovacího okna.

Shrnutí

Drag and drop nalezne své využití v mnoha webových aplikacích a pomůže zvýšit míru jejich integrace se zbytkem systému. Díky nativní podpoře lze např. přetahovat objekty (soubory) z pracovní plochy systému do „drop kontejnerů“ na webové stránce.

K tématu:

Komentáře

Subscribe
Upozornit na
guest
4 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
bauglir

Ahoj,
1/ HTML neumožňuje zadat pouze draggable, specifikace jasně říká, že draggable je enumerated atribut (true, false, auto)
2/ draggable netřeba specifikovat v případě elementů „img“ a „a“ (pokud má href)
3/ uvedené demo funguje pouze ve FF, nikoliv v Chrome, je to způsobenou chybou v implementaci ze strany FF, HTML5 vyžaduje, aby dragenter byl implementován a vracel false, pokud má být akce povolena
http://www.webnt.cz/4-drag-drop/

bauglir

Jak to máte v localhostu? pouštíte to z lokálního web serveru, nebo jako file://? Skoušeli jste implementovat i tu metodu, co jsem psal? Jinak si to budu muset stáhnout a testnout sám :)

PAPoUcH

Teď BFU dotaz , jak do konzole dostat místo tý spletě příkazů jednoduchý log o tom „kam jsem co natahal“ (pro případné uložení výsledku) Děkuji . Prosím nekamenovat :-)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.