• Czas czytania ~ :czas min
  • 18.03.2023

Alpine.js to nowy lekki framework JavaScript, który wykorzystuje podejście polegające na dodawaniu zachowania bezpośrednio w znacznikach HTML. Zgodnie z dokumentacją;

Alpine.js oferuje reaktywny i deklaratywny charakter dużych frameworków, takich jak Vue lub React, przy znacznie niższych kosztach. Możesz zachować swój DOM i posypać się zachowaniem według własnego uznania.

Po dołączeniu kodu – ja używam metody npm – możesz posypać potrzebne zachowanie. Zapewniają schludny przykład dla kart;

<div x-data="{ tab: 'foo' }">
    <button class="button" :class="{ 'button--active': tab === 'foo' }" x-on:click="tab = 'foo'">Foo</button>
    <button class="button" :class="{ 'button--active': tab === 'bar' }" x-on:click="tab = 'bar'">Bar</button>

    <div x-show="tab === 'foo'">Tab Foo</div>
    <div x-show="tab === 'bar'">Tab Bar</div>
</div>

Jeśli rozumiesz podstawy HTML i JavaScript, możesz mieć nadzieję, że dość łatwo zrozumiesz, co się dzieje. Zdarzenia kliknięć są dodawane do <button> elementów za pomocą atrybutux-on:click. Atrybut x-show oblicza, który element ma być wyświetlany. I :class służy do dodawania klasy "active" do przycisku.

Zestaw elementów staje się składnikiem przy użyciu atrybutux-data, który w powyższym przykładzie domyślnie określa widoczną kartę.

Tworzenie listy

przeciągania i upuszczania Ostatnio musiałem zbudować interfejs przeciągania i upuszczania. Normalnie sięgnąłbym po gotowe rozwiązanie, research które pakiety są dostępne i zdecyduj, czego użyć. Miało to na celu uniknięcie problemów z przeglądarką i ponowne wynalezienie koła.

Jednak obsługa JavaScript znacznie się poprawiła na przestrzeni lat, a przeglądarki dodały Natywna obsługa zdarzeń przeciągania i upuszczania. Jest to stosunkowo mały komponent, więc nie miało większego sensu używanie dużej biblioteki, aby osiągnąć to, co było potrzebne.

 

Pierwszym krokiem w budowaniu dowolnego komponentu jest zdefiniowanie kodu HTML, którego chcemy użyć. Użyłem metodologii BEM, aby pomóc konwencji nazewnictwa.

Potrzebujemy dwóch list, każda z własnym nagłówkiem, pojemnikiem i przegrodą.

<div class="drag-and-drop">
    <div class="drag-and-drop__container drag-and-drop__container--from">
        <h3 class="drag-and-drop__title">From</h3>
        <ul class="drag-and-drop__items">
            
            <li class="drag-and-drop__item"></li>
            
        </ul>
    </div>
    <div class="drag-and-drop__divider">⇄</div>
    <div class="drag-and-drop__container drag-and-drop__container--to">
        <h3 class="drag-and-drop__title">To</h3>
        <ul class="drag-and-drop__items">
            
            <li class="drag-and-drop__item"></li>
            
        </ul>
    </div>
</div>

Tworzenie komponentu

Alpine.js Teraz musimy zacząć dodawać nasz Alpine.js. Zacznij od dodania atrybutux-data, aby skonfigurować nasz nowy zakres komponentów.

<div class="drag-and-drop" x-data>
    ...
</div>

Następnie musimy zaznaczyć, które elementy można przeciągnąć. Chcemy, aby można było go <li> przeciągnąć, więc dodajemy do niego atrybut.

<li class="drag-and-drop__item" draggable="true"></li>

Zdarzenia

wiązania Musimy określić, gdzie można upuścić przeciągany element. Musimy powiązać wydarzenie z obydwoma <ul> elementami. Możemy tu użyć atrybutu Alpine.jsx-on.

<ul class="drag-and-drop__items" x-on:drop="">
    ...
</ul>

Są inne wydarzenia, których możemy słuchać, aby dodać afordancji do interakcji użytkownika.

<ul class="drag-and-drop__items"
  x-on:drop=""
  x-on:dragover.prevent=""
  x-on:dragleave.prevent="">
  ...
</ul>

Skonfiguruj dane i przełącz

W tej chwili są to tylko powłoki wydarzeń i tak naprawdę nic nie robią. Aby uczynić je użytecznymi, możemy zacząć manipulować dane dotyczące komponentu. Najpierw musimy ustawić, na jakich właściwościach powinien zależeć komponent. Chcemy wiedzieć podczas dodawania lub usuwania elementu. Możemy skonfigurować te ustawienia domyślne w ten sposób;

<div class="drag-and-drop" x-data="{ adding: false, removing: false }">
    ...
</div>

Teraz możemy manipulować tymi atrybutami w naszych wydarzeniach. Dla naszej listy "Do" chcemy wiedzieć Kiedy dodajemy nowy przedmiot, aktualizujemy adding usługę. Podobnie, zaktualizowalibyśmy removing na liście "Od". Oto jak teraz

<ul class="drag-and-drop__items"
  x-on:drop=""
  x-on:dragover.prevent="adding = true"
  x-on:dragleave.prevent="adding = false">
  ...
</ul>

wygląda lista "Do". Zmieniliśmy niektóre wartości, ale w takim przypadku nie ma widocznych informacji zwrotnych interfejsu użytkownika. Możemy to zrobić, zmieniając style, modyfikując klasy na liście. adding Kiedy nieruchomość jest true możemy dodać Nowa klasa używająca :class atrybutu. Ta klasa jest usuwana, gdy adding właściwość jest false.

<ul class="drag-and-drop__items"
  :class="{ 'drag-and-drop__items--adding': adding }"
  x-on:drop=""
  x-on:dragover.prevent="adding = true"
  x-on:dragleave.prevent="adding = false">
  ...
</ul>

Użylibyśmy tej samej składni podczas usuwania elementów, przełączając removing właściwość i zmieniając klasę. Użyłem klasydrag-and-drop__items--removing, ale moglibyśmy użyć tej samej nazwy klasy dla obu list.

Możemy zastosować ten sam pomysł do stylizacji przedmiotu, który chcemy przeciągnąć. W tej chwili mamy draggable tylko zastosowany atrybut. Pozwala ustawić każdy element jako komponent, powiązać niektóre zdarzenia i zaktualizować klasę.

<li
  class="drag-and-drop__item"
  :class="{ 'drag-and-drop__item--dragging': dragging }"
  draggable="true"
  x-data="{ dragging: false }"
  x-on:dragstart.self="dragging = true"
  x-on:dragend="dragging = false">
  ...
</li>

Uwaga: dodaliśmy .self modyfikator do powiązania zdarzenia. Dokumentacja mówi;

Dodanie .self do detektora zdarzeń spowoduje wyzwolenie programu obsługi tylko wtedy, gdy jest on $event.target samym elementem.

Obsługa przeciągania i upuszczania

Do tej pory powiązaliśmy kilka wydarzeń i wykorzystaliśmy te wydarzenia, aby wprowadzić afordancję interfejsu użytkownika poprzez aktualizację Styl przeciągania elementu i pokazywanie, gdzie element może zostać upuszczony. Następnie musimy faktycznie przesunąć element.

Musimy użyć zdarzenia, dragstart aby zaktualizować dataTransfer obiekt. Ten obiekt przechowuje informacje który jest dostępny dla wydarzeniadrop. Gdy przenosimy nasz przedmiot, ustawiamy effectAllowed właściwość na move. Po drugie, musimy dodać informacje o naszym elemencie do wydarzenia. Ponieważ każdy przedmiot ma id, możemy użyć że jako odniesienie.

x-on:dragstart.self="
  dragging = true;
  event.dataTransfer.effectAllowed = 'move';
  event.dataTransfer.setData('text/plain', event.target.id);
"

Teraz zdarzenie, drop które powiązaliśmy z kontenerem docelowym, ma dostęp do tych informacji. Zamiast używać setData() , możemy użyć getData() metody z dataTransfer obiektu. Spowoduje to zwrócenie id pliku przedmiot, który upuszczamy. Chcemy dołączyć nasz przedmiot do celu. Używając standardowego JavaScript, możemy to zrobić;

x-on:drop.prevent="
  const id = event.dataTransfer.getData('text/plain');
  const target = event.target.closest('ul');
  const element = document.getElementById(id);
  target.appendChild(element);
"

 

Kod Mamy teraz wszystkie poszczególne części do zbudowania komponentu przeciągnij i upuść. Składając to wszystko razem, powinno to wyglądać tak;

<div class="drag-and-drop" x-data="{ adding: false, removing: false }">
    <div class="drag-and-drop__container drag-and-drop__container--from">
        <h3 class="drag-and-drop__title">From</h3>
        <ul
            class="drag-and-drop__items"
            :class="{ 'drag-and-drop__items--removing': removing }"
            x-on:drop="removing = false"
            x-on:drop.prevent="
                const id = event.dataTransfer.getData('text/plain');
                const target = event.target.closest('ul');
                const element = document.getElementById(id);
                target.appendChild(element);
            "
            x-on:dragover.prevent="removing = true"
            x-on:dragleave.prevent="removing = false">
            
            <li
                id="item-1"
                class="drag-and-drop__item"
                :class="{ 'drag-and-drop__item--dragging': dragging }"
                x-on:dragstart.self="
                    dragging = true;
                    event.dataTransfer.effectAllowed = 'move';
                    event.dataTransfer.setData('text/plain', event.target.id);
                "
                x-on:dragend="dragging = false"
                x-data="{ dragging: false }"
                draggable="true">
                Your Item #1
            </li>
        </ul>
    </div>
    <div class="drag-and-drop__divider">⇄</div>
    <div class="drag-and-drop__container drag-and-drop__container--to">
        <h3 class="drag-and-drop__title">To</h3>
        <ul
            class="drag-and-drop__items"
            :class="{ 'drag-and-drop__items--adding': adding }"
            x-on:drop="adding = false"
            x-on:drop.prevent="
                const id = event.dataTransfer.getData('text/plain');
                const target = event.target.closest('ul');
                const element = document.getElementById(id);
                target.appendChild(element);
            "
            x-on:dragover.prevent="adding = true"
            x-on:dragleave.prevent="adding = false">
            
        </ul>
    </div>
</div>

Podsumowanie

Mam nadzieję, że ten samouczek okazał się przydatny, zwłaszcza jeśli jesteś nowy w świecie Alpine.js.

Jest to bardzo prosta implementacja typu "przeciągnij i upuść" z minimalnym JavaScriptem dzięki Alpine.js. Nadal wymaga poprawy, na przykład w celu obsługi ponownego zamawiania na każdej liście. Ale wydaje się, że to dobry punkt wyjścia.

Osobiście zacząłbym teraz przenosić JavaScript do osobnego pliku. Zachowałbym oprawę wydarzenia i przełączanie klas w HTML, ale dłuższe bloki JavaScript byłyby łatwiejsze do utrzymania w określonym pliku JavaScript.

Podgląd

Możesz zobaczyć ten kod w akcji na demonstracji Codepen.


Czytaj więcej...

Comments

No comments yet
Sarah 3:34 PM

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

Replies

Sarah 3:34 PM

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

Sarah 3:34 PM

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

Yurij Finiv

Yurij Finiv

Full stack

O

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297