Prosty i Nowoczesny Framework dla Vue.js
7 godz. 2 min · Vue.js · Full-stack i Programowanie
Wojciech PołowniakSr. Fullstack EngineerW tym projekcie tworzyć będziemy praktyczny projekt - klona Wikipedii! Minipedia pobierze dane z prawdziwego źrodła danych, zewnętrznego API WikiMedia - będzie łudząco podobna do oryginału oraz współdzieliła najważniejsze funkcjonalności, takie jak dostarczanie treści w różnych wersjach językowych, możliwość wyszukiwania artykułów, czy pobieranie najpopularniejszych wpisów dla danego języka. Stworzymy także podstronę wyświetlającą za każdym razem losowy artykuł w danej wersji językowej.Zobaczysz też, jak dokonać migracji ze statycznej strony HTML na Nuxt - oraz jak tworzyć przykładowe komponenty podczas tego procesu.Dzięki temu wszystkiemu, dowiesz się jak wykorzystać nabytą wiedzę w praktyce.
Dzięki Nuxtowi dowiesz się jak optymalizować Twoje strony www z duchem idei progressive enhancement, dostarczając coraz to lepsze doświadczenia dla swoich użytkowników oraz tworząc aplikację napisaną w 100% w JavaScript, która będzie działała nawet wtedy, gdy użytkownik jawnie wyłączy go w przeglądarce! To wszystko za SSR (Server Side Rendering), dzięki któremu treści będą gotowe do konsumpcji już przy wstępnej, pierwszej odpowiedzi z serwera WWW.Oczywiście, ma to swoje implikacje na wydajność naszej aplikacji - sprawiając że Lighthouse czy optymalizacja pod SEO staje się coraz prostsza!
Czymże jest ekosystem danego frameworka bez wsparcia społeczności! Dlatego podczas tego kursu nauczysz się instalować i wykorzystywać różne pluginy i moduły, które zaoszczędzą Ci dużo czasu. Dowiesz się też, jak tworzyć własne moduły - które rozszerzą działanie Twojej aplikacji Nuxt w sposób czysty i zarządzalny.
Nuxt jest frameworkiem w którym pracujemy zarówno po stronie front-endu, jak i back-endu. W związku z czym, stworzymy swoje własne API (bazujące na express.js) które będzie pewnego rodzaju pośrednikiem pomiędzy API WikiMedia oraz Twoją aplikacją internetową.
W tym kursie, dowiesz się także jak tworzyć swoje własne Middleware'y - czyli fragmenty kodu wywoływane pomiędzy przechodzeniem między stronami, czy podczas innych zapytań HTTP.Dodatkowo, zobaczysz jakie narzędzia daje nam Nuxt aby tworzyć progresywne aplikacje internetowe, oferując wsparcie dla takich funkcjonalności jak np. animacje między przejściami pojedynczymi podstronami naszego serwisu.
Tajemnicze i18n - czyli numeronim odpowiadający angielskiemu słowu "internalisation" - odnosi się w kontekście web developmentu do tłumaczenia danych na różne języki. Podczas realizacji projektu Minipedii, nie tylko wykorzystamy standardowe podejście do tłumaczeń stałych elementów naszego interfejsu użytkownika, ale także przetłumaczymy same dane zwracane z API, wykorzystując inną wersję językową w zależności od preferencji użytkownika!
Poznasz też kilka ciekawych pluginów i rozwiązań dotyczących optymalizacji pod SEO - poza faktem, że podejście spełniające intencje użytkownika jest najlepszym, co możemy zrobić - pluginy generujące nam mapę stron automatycznie na podstawie zadeklarowanych przez nas podstron, czy generatory danych jsonld pomogą w pozycjonowaniu Twojej wydajnej aplikacji jeszcze wyżej w hierarchii wyszukiwarek.
Aby móc efektywnie korzystać z tego kursu, powinieneś posiadać średnio zaawansowaną wiedzę z kategorii Front End, z naciskiem na umiejętność posługiwania się JavaScriptem oraz solidne podstawy NodeJS. Konieczna jest znajomość Vue, jako że Nuxt jest frameworkiem korzystającym z niego u swoich podstaw. Jeśli czujesz się dość swobodnie w wyżej wymienionych aspektach web developmentu, ten kurs będzie idealny dla Ciebie.
W tej lekcji stworzymy wyszukiwarkę
wg się, która będzie pobierała proponowane artykuły z Wikipedii
i dzięki niej będziemy mogli wejść i obejrzeć dany artykuł.
Zobaczymy jak nam to pójdzie.
W związku z czym pierwsze co trzeba zrobić
to znaleźć miejsce, gdzie znajduje się ten oto search box.
Więc przejdźmy do naszego komponentu
Default Layout i tutaj widzimy, że znajdzie się na samym
dole ikonka lupy oraz informacja, że jest to nasza wyszukiwarka.
To możemy oczywiście z Translate, choć nie będziemy tego w tym momencie robili.
Szkoda troszkę czasu więc.
Stwórzmy po pierwsze
event i na RE, które będą nasłuchiwał na zdarzenia na tym elemencie input.
Czyli muszę jeszcze komentujemy na chwilę.
Tutaj sobie zrobimy funkcję center
click, która będzie obsługiwała kliknięcia w nasz input.
A w sumie bardziej handler input
i ta funkcja zostanie przypisana do zdarzenia natywnego input.
Czyli w momencie kiedy jest jakiś input na naszym.
I kłucie. Jakkolwiek to brzmi.
Generalnie, gdy są dane wprowadzone w to
pole typu input, no to wtedy wywoła się nasza funkcja input
i ta funkcja zostanie zdefiniowana tutaj w sekcji logicznej tego komponentu.
I w sumie może przenieśmy też ten komponent od razu do.
Katalog components search box.
Tak będzie czyściej, Nie będziemy musieli
brudzić naszego layoutu komponentem, więc to sobie przeniesiemy stąd.
Wklejamy tutaj.
Kompleks.
DF.
Temple.
Zamykamy piwa.
Script.
Script.
Niestety bez auto zamykania tagów troszkę można się pogubić.
Export default.
Komponent.
I tutaj wstawiamy nasz komponent, który
kupowaliśmy, w związku z czym tworzymy sobie metodę.
Metodę endo input.
I tutaj będziemy mieli wielu.
Albo event, na którym będziemy musieli pobrać
jego target i wtedy wartość, ale możemy to sobie logować.
Valium.
Nie musimy tego tutaj dodać do naszego.
Layout. Zapisujemy, sprawdzamy.
Kompan powinien tutaj być i daje.
Zobaczmy czy w newsach faktycznie pisze
nam się w momencie gdy robimy jakieś ruchy klawiaturą i faktycznie jest input event.
W związku z czym jeżeli to jest event to
musimy pobrać z niego wartość, więc w naszym komponencie sandbox zamiast.
Walu.
Dajemy sobie tutaj event jako nazwę zmiennej.
I teraz Event target
value będzie zawierało to co właśnie wpisaliśmy w naszego boxa.
I teraz gdy to wpisujemy to faktycznie widzimy treść, wpisywano.
Co trzeba zrobić dalej, to przekazać te informacje do naszego API.
Oczywiście moglibyśmy to zrobić naprawdę poprawnie w kontekście pracy z WU.
Tzn. Stworzyć eventami, które będą wysyłały
informacje o zdarzeniu, które wydarzyło się wewnątrz tego komponentu.
Następnie propagować te dane z powrotem do komponentu.
Zrobić wsparcie dla modelu na naszych
custom komponentach, ale zajmie to nam faktycznie sporo czasu.
Jest taką typowo WU rzeczą, a nie
konkretnie next ową jak tworzyć rozwiązania.
W związku z czym nie zrobimy tego, po prostu będziemy na każde handler input.
Być może na debiucie
robiłeś zapytanie do naszego API o jakie informacje znajdują się na
na stronie Wikipedii na dany temat, w związku z czym przejdźmy do API wiki.
Jest.
I tutaj mamy sekcję Serge.
Jest również prefiks Serge, ale jest to
taki, który nam nie będzie potrzebny, bo nam
zależy tylko i wyłącznie na wpisywaniu do danej frazy i szukaniu jej.
W danej wersji językowej, w związku z czym kopiujemy tą funkcję.
Widzimy, że mamy tu bezpośrednie odwołanie do funkcji wiki.
Więc możemy przejść do naszego routera.
Viking jest.
I ponownie kolejny endpoint.
Stworzyć.
Być może tutaj analogicznie do zw.
Chyba się uda użyć tej funkcji ponownie.
Naprawdę nie chcę dopisywać już, więc zobaczmy tutaj FN i zamiast master J.
Tutaj ta właśnie funkcja.
Właśnie na tych bezpośrednich
zapytań to się powinno nam udać, w związku z czym tutaj.
W naszym boksie powinniśmy mieć dostęp do akcji Asa.
Tak mi się wydaje.
Konsolę mogę bez.
Akcja.
Miejmy nadzieję, że to co się tam znajduje.
Strona główna piszemy coś i faktycznie
jest tutaj akcja, więc możemy robić zapytania na front endzie.
Czyli w tym momencie piszemy kod typowo frontend.
I pobierzemy sobie.
Query.
I będziemy robić zapytanie
do Axis a do naszego API i możemy to pobrać sobie z naszego.
Routingu.
Fragment kodu.
I oczywiście zaraz czujemy gola.
Odpowiedniego projektu, który chcemy
odebrać, czyli w naszym przypadku będzie to serwis.
Nie potrzebujemy także potrzebujemy tylko i wyłącznie język, język.
Wejdziemy z bez.
I 18 n kal.
I tutaj zrobiłem sobie konsolowe.
Z wartością.
Parametr, który przyjmuje.
Według dokumentacji dokumentacji to oprócz query mamy też limit.
W związku z czym nasz endpoint powinien przyjąć te dwa parametry.
Można opcjonalnie przekazać, ale jeśli chcemy wszystkie proponowane wyniki.
Dla danej frazy, ale nas to nie interesuje.
W związku z tym.
Rozszerzymy ten nasz endpoint.
No i przez to rozszerzenie niestety nie możemy wykorzystać tego samego miejsca.
Bardzo chciałem, ale niestety jest to zbyt specyficzna zależność.
W każdym razie da się takie coś zrobić,
więc jeśli chcecie to śmiało myślcie jak ulepszyć, jak coś zrobić.
Tutaj jest language, tutaj będzie query query i jeszcze do tego limit limits.
I analogicznie.
Limit no limit.
Oraz tutaj.
Query nie potrzebujemy tych tutaj folderów.
I w tym momencie zmieniamy most na.
I będziemy przekazywali tę informację jako następne parametry do tej funkcji.
Czyli tutaj przekazujemy jako pierwsze
query, jako drugi limit i zobaczmy co się stanie, jeżeli to zapiszemy.
I przekażemy do naszej funkcji jako query query.
Oraz limit huśtawki na 5.
Wracamy do naszego komponentu.
Tutaj nam się coś rozjechało.
Wizard, Word, Wand.
Czyli nie zrobiliśmy tego funkcją asynchronicznym.
Naprawiamy nasz błąd.
I ponownie próbujemy.
Powiedzmy wpisać.
A bo to na każde literki będzie nam robiło zapytanie, więc lepiej to ograniczyć.
I faktycznie widzimy, że zwróciło nam się 5 wyników stron.
To, co moglibyśmy zrobić w tym momencie to.
View Event Liste North TVS.
Jest to taka specjalna funkcja.
Która pozwoli nam.
Ograniczyć liczbę requestów czy liczbę wywoływania danej funkcji.
Do jakiejś określonej wartości.
Wydaje mi się, że VU powinno mieć input dip z WU jako domyślną dyrektywę.
Zobaczmy na Stack Overflow.
Niestety nie widzę tutaj prostego
rozwiązania, w związku z czym zostawię to tak jak jest.
Nie będzie to niestety najbardziej
optymalny kod, ale generalnie to co można zrobić to na każdą literkę
zrobić funkcję wywołującą, która dopiero po
kilku sekundach w momencie gdy skończymy pisać będzie wywoływała nasz endpoint.
Ale na tym etapie zróbmy to po prostu na
tej zasadzie, że wpisujemy Janusz i faktycznie robi się 5 requestów.
Jest to bardzo nie optymalne.
W związku z tym wykorzystamy zapytanie tutaj i przekażemy je dalej np.
do naszego data.
Czyli zrobimy sobie tutaj pole data.
I wydaje mi się, że data powinna zwracać funkcję.
No zobaczymy jak to wygląda w WB.
Szczerze mówiąc nawet nie pamiętam Data Vue.
Tak. Data jest funkcją, która zwraca obiekt
dobrze pamiętamy, w związku z czym robimy tutaj funkcję obiekt i będzie to.
Available options.
Domyślnie będzie to pusta lista.
I w momencie kiedy to nam się zaktualizuje to będziemy atakować dysk evil bo
poprzez modem to sobie skopiować, żeby nie było problemu z literówkami.
I pobierzemy stąd jedną wartość.
To będzie request albo response bardziej.
I tutaj this post pobierzemy z naszej strony jako results, results i sales.
Powinno nam się wyświetlić, w związku z czym możemy spróbować to pokazać tutaj.
Owszem, zapisujemy.
Tutaj nie daliśmy przecinka.
Trzeba pamiętać o przecinkach i średnicach.
I tutaj chyba jest jeden nawias za dużo.
Zapisujemy.
I w tym momencie nam działa.
Gdy wpiszemy dowolną literkę, to pojawia nam się tutaj proponowane wartości.
Oczywiście nie chcemy aby nasz input się przesuwał, w związku z czym
my się tego pozbędziemy z widoku i po prostu na ebay lub poprzez.
Będziemy dodawać Data lista tutaj.
Czyli tatar jest owszem w FR.
Whirlpool Option.
Option options Value równa się open,
ale po prostu niech nie zostanie w ten sposób zapiszemy.
I co się w tym momencie stanie, gdy napiszemy?
Janusz to w tym momencie nasz data list powinien rozpropagować się różnymi danymi.
I jest propagował się, bo tutaj jest po
prostu to przekazywane jako bezpośredni atrybut, a nie jako wartość dynamiczna.
Więc tutaj sobie robimy.
Janusz.
I widzimy proponowane opcje, które jeśli
faktycznie zrobią na nich enter to to się nam wypełni.
I teraz musimy w momencie wyboru danej
opcji po prostu ją wyświetlić, tutaj przekierować do odpowiedniego patcha.
Problem polega na tym, że.
Data list nie ma na sobie żadnych event i serwerów.
Jest ciężko troszkę to wykryć.
W związku z czym my zrobimy takie rozwiązanie, że będzie
tutaj osobny przycisk, który klikając będziemy wybierali.
Wartość i przekierowywanie użytkownika na daną stronę.
Przejdźmy sobie tutaj.
Widzę, że z poprzedniej lekcji chyba się nie zapisało.
Nasze zmiany dotyczące wersji językowych.
W każdym razie.
Zapiszemy to. I metody.
Tutaj samiec tak samo wypisze co dzieje.
Zapisujemy.
I mam taką nadzieję, że w momencie gdy.
Piszemy coś tutaj.
I zrobimy enter to coś tam się wydarzy.
I faktycznie chyba przez to, że to jest w formularzu to nam przekierował.
Możemy zrobić tutaj event event.
Default.
Gdyby domyślne przekierowanie się nie wydarzało.
Enter i faktycznie widzimy sami event.
Tutaj nam zadziałał.
Piszemy sobie Janusz
Korczak i po kliknięciu możemy zrobić sami ręcznie i on też się wywoła.
Pójdziemy tą drogą.
Więc robimy sobie tutaj bez.
Router push i tutaj przekazujemy teraz jako dysk local.
Ks. .
I przekażemy tutaj wiki.
Po prostu jako drugi parametr do local paf przekazujemy parametr.
Gdzie tutaj?
Wartością będzie natomiast fakt.
Zobaczymy co się z tego stanie w sumie, bo nawet nie jestem pewien.
Event jest. Czemu?
Komentujemy to sobie cancel event value.
I wyślemy.
I tutaj będziemy mieli wartości, czyli target form.
I tutaj pierwszy element to jest nasz import i na nim możemy pobrać jego.
Wartość.
W związku z czym jak zrobimy sobie tutaj event target?
0.
Wydaje mi się, że to powinno zadziałać Valium.
To po wpisaniu tutaj wartości z enterem faktycznie dostajemy tę wartość, w związku
z czym spróbujmy zrobić tutaj tego posta z tą wartością.
Czyli const query to jest to.
I tutaj w powiedzmy query query zapiszemy.
Test.
Sam mit.
I zobaczmy, kiedy nas przekieruje.
Przekierował nas na wiki bez żadnego dodatkowego parametru, więc po prostu
prawdopodobnie musimy przekazać to w tym miejscu obok.
Lokal.
I tutaj query.
Usuniemy.
Zapiszemy.
I jeszcze jedna próba.
Janusz.
Korczak Sam mit.
I przekierował nas na odpowiednią lokację, w związku z czym nasza
wyszukiwarka już działa i już jesteśmy w stanie z niej korzystać.
Tutaj możemy nawet zostawiać nasze wartości i zastanawiam
się, czemu jest tutaj tylko jakieś przekierowanie na tamten świat.
Prawdopodobnie
dlatego właśnie, że czasami query robią się w momencie nawet wtedy, gdy nie ma
wartości swift nad query, to po prostu ignorujemy ten input.
No i oczywiście moglibyśmy tutaj zrobić
rzeczy jak poprawne podzielenie tego komponentu na
różne odpowiedzialności, ale jesteśmy w stanie przejść na stronę główną.
W języku.
I wyszukać informacji w danym języku.
Czyli jeśli teraz wpiszemy sobie.
Batman albo jakiś taki film.
No to faktycznie.
Język zmienił się na francuski i widzimy, że dany wpis jest w języku
francuskim, ponieważ respektowany jest język, który wybraliśmy wcześniej
i tego typu rzeczy jesteśmy w stanie zrobić naprawdę szybko w.
Jeśli zrozumiemy dobrze fundamenty tego frameworka,
zachęcam, aby jeżeli faktycznie robicie produkcyjne projekty
używać jakiś frameworków do Julia, ponieważ takie rozwiązania jak na przykład
z tym boxem z data listen faktycznie działa i jest semantycznie poprawne w
kontekście accessibility czy innych tego typu problemów.
Ale jeśli chodzi o sterowanie czy pracę z
tym na dłuższą metę to może to być problematyczne.
Zmiany wprowadzone w lekcji · 17 min
diff --git a/33/minipedia/api/routes/wiki.js b/33/minipedia/api/routes/wiki.js
index d9476ce..c03563e 100644
--- a/33/minipedia/api/routes/wiki.js
+++ b/33/minipedia/api/routes/wiki.js
@@ -64,4 +64,25 @@ router.get('/mostViewed/lang/:lang', async (req, res) => {
}
})
+router.get('/search/lang/:lang/query/:query/limit/:limit', async (req, res) => {
+ const lang = req.params.lang || 'en';
+ const limit = req.params.limit;
+ const query = req.params.query;
+
+ const Wiki = WikiJs({
+ apiUrl: `https://${lang}.wikipedia.org/w/api.php`,
+ headers: { 'User-Agent': process.env.BOT_USER_AGENT}
+ });
+
+ try {
+ const randomArticles = await Wiki.search(query, limit);
+
+ return res.status(200).json(randomArticles);
+
+ } catch (e) {
+ console.error(e);
+ return res.status(500).json(e);
+ }
+})
+
export default router;
\ No newline at end of file
diff --git a/33/minipedia/components/SearchBox.vue b/33/minipedia/components/SearchBox.vue
new file mode 100644
index 0000000..26840ad
--- /dev/null
+++ b/33/minipedia/components/SearchBox.vue
@@ -0,0 +1,34 @@
+<template>
+<form @submit="handleSubmit">
+ <input type="search" list="autocomplete" class="site-search" placeholder="🔍 Search minipedia"
+ @input="handleInput">
+ <datalist id="autocomplete">
+ <option v-for="options in availableOptions" :value="options"></option>
+ </datalist>
+ <button type="submit">Submit</button>
+</form>
+</template>
+<script>
+export default {
+ data() {
+ return {
+ availableOptions: [],
+ };
+ },
+ methods: {
+ handleSubmit(ev) {
+ const query = ev.target[0].value;
+ this.$router.push({ path: this.localePath(`/wiki/${query}`)})
+ ev.preventDefault();
+ },
+ async handleInput(ev) {
+ const query = ev.target.value;
+ if (!query) {
+ return;
+ }
+ const response = await this.$axios.$get(`/api/wiki/search/lang/${this.$i18n.locale}/query/${query}/limit/5`);
+ this.availableOptions = response.results;
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/33/minipedia/layouts/default.vue b/33/minipedia/layouts/default.vue
index 9d422ff..89daca9 100644
--- a/33/minipedia/layouts/default.vue
+++ b/33/minipedia/layouts/default.vue
@@ -63,10 +63,7 @@
</li>
</ul>
- <input type="search" list="autocomplete" class="site-search" placeholder="🔍 Search minipedia">
- <datalist id="autocomplete">
- <!-- <option value=""></option> -->
- </datalist>
+ <SearchBox />
</header>
<Nuxt />