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.