Prosta aplikacja
Stwórzmy prostą aplikację, która pokaże, jak wykonać większość najważniejszych czynności podczas korzystania z Mithril.
Interaktywny przykład końcowego rezultatu można zobaczyć tutaj
Najpierw stwórzmy punkt wejścia dla aplikacji. Utwórz plik index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Moja aplikacja</title>
</head>
<body>
<script src="bin/app.js"></script>
</body>
</html>
Linia <!DOCTYPE html>
informuje przeglądarkę, że jest to dokument HTML5. Pierwszy meta tag charset
określa kodowanie znaków dokumentu, a meta tag viewport
definiuje sposób skalowania strony przez przeglądarki mobilne na urządzeniach mobilnych. Tag title
zawiera tekst, który ma być wyświetlany na karcie przeglądarki dla tej aplikacji, a tag script
wskazuje ścieżkę do pliku JavaScript, który kontroluje działanie aplikacji.
Moglibyśmy stworzyć całą aplikację w jednym pliku JavaScript, ale utrudniłoby to późniejsze zarządzanie kodem. Zamiast tego podzielmy kod na moduły i zmontujmy te moduły w pakiet bin/app.js
.
Istnieje wiele sposobów konfiguracji narzędzia do pakowania (bundlera), ale większość z nich jest dystrybuowana za pośrednictwem npm. W rzeczywistości większość nowoczesnych bibliotek i narzędzi JavaScript jest dystrybuowana w ten sposób, w tym Mithril. Aby pobrać npm, zainstaluj Node.js; npm jest instalowany automatycznie wraz z nim. Po zainstalowaniu Node.js i npm otwórz wiersz poleceń i uruchom to polecenie:
npm init -y
Jeśli npm jest zainstalowany poprawnie, zostanie utworzony plik package.json
. Ten plik zawiera podstawowe metadane projektu. Możesz edytować informacje o projekcie i autorze w tym pliku.
Aby zainstalować Mithril.js, postępuj zgodnie z instrukcjami na stronie instalacji. Po utworzeniu szkieletu projektu z zainstalowanym Mithril.js, jesteśmy gotowi do rozpoczęcia tworzenia aplikacji.
Zacznijmy od stworzenia modułu do przechowywania stanu aplikacji. Utwórzmy plik o nazwie src/models/User.js
// src/models/User.js
var User = {
list: [],
};
module.exports = User;
Teraz dodajmy kod do pobierania danych z serwera. Aby komunikować się z serwerem, możemy użyć narzędzia XHR Mithril.js, m.request
. Najpierw zaimportujmy Mithril.js do modułu:
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
};
module.exports = User;
Następnie zdefiniujemy funkcję, która wykona zapytanie XHR. Nazwijmy ją loadList
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
// TODO: make XHR call
},
};
module.exports = User;
Następnie możemy dodać wywołanie m.request
, aby wykonać żądanie XHR. W tym samouczku będziemy używać REM (MARTWY LINK, FIXME: https //rem-rest-api.herokuapp.com/) API, czyli atrapy REST API zaprojektowanego do szybkiego prototypowania, do wykonywania zapytań XHR. API to zwraca listę użytkowników z endpointu GET https://mithril-rem.fly.dev/api/users
. Użyjemy m.request
, aby wysłać zapytanie XHR i wypełnić nasze dane danymi zwróconymi przez ten endpoint.
Uwaga: pliki cookie stron trzecich mogą być włączone, aby endpoint REM działał.
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users',
withCredentials: true,
})
.then(function (result) {
User.list = result.data;
});
},
};
module.exports = User;
Opcja method
to metoda HTTP. Aby pobrać dane z serwera bez powodowania efektów ubocznych na serwerze, musimy użyć metody GET
. url
to adres endpointu API. Linia withCredentials: true
wskazuje, że używamy plików cookie (co jest wymaganiem dla REM API).
Funkcja m.request
zwraca Promise, który po rozwiązaniu zawiera dane z endpointu. Domyślnie Mithril.js zakłada, że odpowiedź HTTP jest w formacie JSON i automatycznie parsuje ją do obiektu lub tablicy JavaScript. Funkcja zwrotna (callback) przekazana do .then
zostanie wykonana po zakończeniu zapytania XHR. W tym przypadku funkcja zwrotna przypisuje tablicę result.data
do User.list
.
Zauważ, że mamy również instrukcję return
w loadList
. Jest to ogólnie dobra praktyka podczas pracy z Promise, ponieważ pozwala na zarejestrowanie dodatkowych funkcji zwrotnych, które zostaną wykonane po zakończeniu zapytania XHR.
Ten prosty model udostępnia dwa elementy: User.list
(tablica obiektów użytkownika) i User.loadList
(metoda, która wypełnia User.list
danymi z serwera).
Teraz stwórzmy moduł widoku (view), abyśmy mogli wyświetlać dane z naszego modułu modelu Użytkownika.
Utwórz plik o nazwie src/views/UserList.js
. Najpierw zaimportujmy Mithril.js i nasz model, ponieważ będziemy musieli użyć obu:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
Następnie stwórzmy komponent Mithril.js. Komponent to po prostu obiekt, który ma metodę view
:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
view: function () {
// TODO add code here
},
};
Domyślnie widoki (views) Mithril.js są opisywane za pomocą hyperscript. Hyperscript oferuje zwięzłą składnię, którą łatwiej formatować (np. wcięcia) niż HTML w przypadku złożonych struktur. Ponieważ jest to po prostu JavaScript, można wykorzystać bogaty ekosystem narzędzi JavaScript. Na przykład:
- Możesz użyć Babel do transpilowania kodu ES6+ do ES5 (dla Internet Explorera) oraz JSX (rozszerzenia składni podobnego do HTML) do wywołań funkcji hyperscript.
- Możesz użyć ESLint do łatwego lintowania bez specjalnych wtyczek.
- Możesz użyć Terser lub UglifyJS (tylko ES5) do łatwego minimalizowania kodu.
- Możesz użyć Istanbul do pokrycia kodu.
- Możesz użyć TypeScript do łatwej analizy kodu. (Dostępne są definicje typów wspierane przez społeczność, więc nie musisz tworzyć własnych.)
Zacznijmy od hyperscript i stwórzmy listę elementów. Hyperscript to idiomatyczny sposób używania Mithril.js, ale JSX działa całkiem podobnie.
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
view: function () {
return m('.user-list');
},
};
Ciąg znaków ".user-list"
to selektor CSS, gdzie .user-list
odnosi się do klasy. Zatem ten kod generuje element <div class="user-list"></div>
.
Teraz odwołajmy się do listy użytkowników z modelu, który stworzyliśmy wcześniej (User.list
), aby dynamicznie iterować po danych:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
view: function () {
return m(
'.user-list',
User.list.map(function (user) {
return m('.user-list-item', user.firstName + ' ' + user.lastName);
})
);
},
};
Ponieważ User.list
jest tablicą JavaScript, a widok hyperscript to po prostu JavaScript, możemy iterować po tablicy za pomocą metody .map
. Powoduje to utworzenie tablicy vnode'ów reprezentujących listę elementów div
, z których każdy zawiera imię i nazwisko użytkownika.
Problemem, oczywiście, jest to, że nigdy nie wywołaliśmy funkcji User.loadList
. W związku z tym User.list
pozostaje pustą tablicą, co skutkuje wyrenderowaniem pustej strony. Aby funkcja User.loadList
została wywołana podczas renderowania komponentu, wykorzystamy metody cyklu życia:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
oninit: User.loadList,
view: function () {
return m(
'.user-list',
User.list.map(function (user) {
return m('.user-list-item', user.firstName + ' ' + user.lastName);
})
);
},
};
Zauważ, że dodaliśmy metodę oninit
do komponentu, która wywołuje User.loadList
. Oznacza to, że podczas inicjalizacji komponentu zostanie wywołana funkcja User.loadList
, co spowoduje wysłanie zapytania XHR. Gdy serwer zwróci odpowiedź, User.list
zostanie wypełnione.
Zauważ również, że nie zrobiliśmy oninit: User.loadList()
(z nawiasami na końcu). Różnica polega na tym, że oninit: User.loadList()
wywołuje funkcję raz i natychmiast, ale oninit: User.loadList
wywołuje tę funkcję tylko wtedy, gdy komponent jest renderowany. To ważna różnica, często powodująca błędy u początkujących programistów JavaScript. Bez nawiasów funkcja zostanie wywołana dopiero w momencie renderowania komponentu. Wywołanie funkcji z nawiasami spowoduje natychmiastowe wykonanie zapytania XHR, nawet jeśli komponent nie zostanie wyrenderowany.
Dodatkowo, jeśli komponent zostanie kiedykolwiek ponownie utworzony (np. podczas nawigacji w aplikacji), funkcja nie zostanie wywołana ponownie, co może być niezgodne z oczekiwaniami.
Wyrenderujmy widok (view) z pliku punktu wejścia src/index.js
, który stworzyliśmy wcześniej:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
m.mount(document.body, UserList);
Funkcja m.mount
renderuje wskazany komponent (UserList
) w elemencie DOM (document.body
), usuwając jego dotychczasową zawartość. Otwarcie pliku HTML w przeglądarce powinno teraz wyświetlić listę imion i nazwisk osób.
Obecnie lista wygląda dość prosto, ponieważ nie zdefiniowano żadnych stylów. Dodajmy więc kilka. Najpierw stwórzmy plik o nazwie styles.css
i dołączmy go do pliku index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Moja aplikacja</title>
<link href="styles.css" rel="stylesheet" />
</head>
<body>
<script src="bin/app.js"></script>
</body>
</html>
Teraz możemy ostylować komponent UserList
:
.user-list {
list-style: none;
margin: 0 0 10px;
padding: 0;
}
.user-list-item {
background: #fafafa;
border: 1px solid #ddd;
color: #333;
display: block;
margin: 0 0 1px;
padding: 8px 15px;
text-decoration: none;
}
.user-list-item:hover {
text-decoration: underline;
}
Ponowne załadowanie okna przeglądarki powinno teraz wyświetlić ostylowane elementy.
Zaimplementujmy routing w naszej aplikacji.
Routing oznacza powiązanie widoku (ekranu) z unikalnym adresem URL, aby umożliwić przechodzenie z jednej "strony" do drugiej. Mithril.js jest przeznaczony dla Single Page Applications (SPA), więc te "strony" niekoniecznie są różnymi plikami HTML w tradycyjnym tego słowa znaczeniu. Zamiast tego routing w aplikacjach jednostronicowych zachowuje ten sam plik HTML przez cały okres jego istnienia, ale zmienia stan aplikacji za pomocą JavaScript. Routing po stronie klienta ma tę zaletę, że unika migania pustego ekranu między przejściami stron i może zmniejszyć ilość danych wysyłanych z serwera, gdy jest używany w połączeniu z architekturą zorientowaną na usługi internetowe (tj. aplikacja, która pobiera dane jako JSON zamiast pobierania wstępnie renderowanych fragmentów obszernego HTML).
Możemy dodać routing, zmieniając wywołanie m.mount
na wywołanie m.route
:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
m.route(document.body, '/list', {
'/list': UserList,
});
Wywołanie m.route
określa, że aplikacja będzie renderowana w document.body
. Argument "/list"
definiuje domyślną ścieżkę. Oznacza to, że użytkownik zostanie przekierowany na tę ścieżkę, jeśli spróbuje przejść do nieistniejącej ścieżki. Obiekt {"/list": UserList}
tworzy mapę istniejących ścieżek i przypisuje im odpowiednie komponenty.
Odświeżenie strony w przeglądarce powinno teraz dołączyć #!/list
do adresu URL, aby wskazać, że routing działa. Ponieważ ta ścieżka renderuje UserList, nadal powinniśmy widzieć listę osób na ekranie, jak poprzednio.
Sekwencja znaków #!
jest znana jako hashbang (znak #!) i jest powszechnie stosowana w routingu po stronie klienta. Prefiks hashbang można skonfigurować za pomocą m.route.prefix
. Niektóre konfiguracje wymagają obsługi zmian po stronie serwera, więc po prostu będziemy nadal używać hashbang dla reszty tego samouczka.
Dodajmy kolejną ścieżkę do naszej aplikacji do edycji użytkowników. Najpierw stwórzmy moduł o nazwie views/UserForm.js
// src/views/UserForm.js
module.exports = {
view: function () {
// TODO implement view
},
};
Następnie możemy zaimportować (require
) ten nowy moduł z src/index.js
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
var UserForm = require('./views/UserForm');
m.route(document.body, '/list', {
'/list': UserList,
});
I wreszcie, możemy stworzyć ścieżkę, która się do niego odwołuje:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
var UserForm = require('./views/UserForm');
m.route(document.body, '/list', {
'/list': UserList,
'/edit/:id': UserForm,
});
Zauważ, że nowa ścieżka zawiera :id
. Jest to parametr ścieżki, który można traktować jako symbol wieloznaczny (wildcard). Ścieżka /edit/1
spowoduje wyświetlenie komponentu UserForm
z parametrem id
ustawionym na "1"
. /edit/2
również rozwiązałoby się do UserForm
, ale z id
równym "2"
. I tak dalej.
Zaimplementujmy komponent UserForm
, aby mógł reagować na te parametry ścieżki:
// src/views/UserForm.js
var m = require('mithril');
module.exports = {
view: function () {
return m('form', [
m('label.label', 'Imię'),
m('input.input[type=text][placeholder=Imię]'),
m('label.label', 'Nazwisko'),
m('input.input[placeholder=Nazwisko]'),
m('button.button[type=submit]', 'Zapisz'),
]);
},
};
I dodajmy więcej stylów do styles.css
:
/* styles.css */
body,
.input,
.button {
font: normal 16px Verdana;
margin: 0;
}
.user-list {
list-style: none;
margin: 0 0 10px;
padding: 0;
}
.user-list-item {
background: #fafafa;
border: 1px solid #ddd;
color: #333;
display: block;
margin: 0 0 1px;
padding: 8px 15px;
text-decoration: none;
}
.user-list-item:hover {
text-decoration: underline;
}
.label {
display: block;
margin: 0 0 5px;
}
.input {
border: 1px solid #ddd;
border-radius: 3px;
box-sizing: border-box;
display: block;
margin: 0 0 10px;
padding: 10px 15px;
width: 100%;
}
.button {
background: #eee;
border: 1px solid #ddd;
border-radius: 3px;
color: #333;
display: inline-block;
margin: 0 0 10px;
padding: 10px 15px;
text-decoration: none;
}
.button:hover {
background: #e8e8e8;
}
W tej chwili ten komponent nie robi nic, aby reagować na zdarzenia użytkownika. Dodajmy kod do naszego modelu User
w src/models/User.js
. Tak wygląda teraz kod:
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users',
withCredentials: true,
})
.then(function (result) {
User.list = result.data;
});
},
};
module.exports = User;
Dodajmy kod, który pozwoli nam załadować pojedynczego użytkownika
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users',
withCredentials: true,
})
.then(function (result) {
User.list = result.data;
});
},
current: {},
load: function (id) {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users/' + id,
withCredentials: true,
})
.then(function (result) {
User.current = result;
});
},
};
module.exports = User;
Zauważ, że dodaliśmy właściwość User.current
oraz metodę User.load(id)
, która ją wypełnia. Możemy teraz wypełnić widok (view) UserForm
za pomocą tej nowej metody:
// src/views/UserForm.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
oninit: function (vnode) {
User.load(vnode.attrs.id);
},
view: function () {
return m('form', [
m('label.label', 'Imię'),
m('input.input[type=text][placeholder=Imię]', {
value: User.current.firstName,
}),
m('label.label', 'Nazwisko'),
m('input.input[placeholder=Nazwisko]', { value: User.current.lastName }),
m('button.button[type=submit]', 'Zapisz'),
]);
},
};
Podobnie jak komponent UserList
, oninit
wywołuje User.load()
. Pamiętasz, że mieliśmy parametr ścieżki o nazwie :id
na ścieżce "/edit/:id": UserForm
? Parametr ścieżki staje się atrybutem vnode komponentu UserForm
. Przejście do ścieżki /edit/1
spowoduje, że vnode.attrs.id
będzie miało wartość "1"
.
Teraz zmodyfikujmy widok (view) UserList
, abyśmy mogli nawigować stamtąd do UserForm
:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
oninit: User.loadList,
view: function () {
return m(
'.user-list',
User.list.map(function (user) {
return m(
m.route.Link,
{
class: 'user-list-item',
href: '/edit/' + user.id,
},
user.firstName + ' ' + user.lastName
);
})
);
},
};
Zamieniliśmy vnode .user-list-item
na m.route.Link
z tą samą klasą i zawartością. Dodaliśmy atrybut href
, który wskazuje na żądaną ścieżkę. Kliknięcie linku spowoduje zmianę części adresu URL następującej po hashbang #!
, co umożliwi zmianę ścieżki bez przeładowania strony HTML. Mechanizm ten wykorzystuje element <a>
do utworzenia linku, a cała logika jest obsługiwana automatycznie.
Jeśli odświeżysz stronę w przeglądarce, powinieneś teraz móc kliknąć osobę i przejść do formularza. Powinieneś również móc nacisnąć przycisk Wstecz w przeglądarce, aby wrócić z formularza do listy osób.
Formularz nadal nie zapisuje się po kliknięciu "Zapisz". Sprawmy, aby ten formularz działał:
// src/views/UserForm.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
oninit: function (vnode) {
User.load(vnode.attrs.id);
},
view: function () {
return m(
'form',
{
onsubmit: function (e) {
e.preventDefault();
User.save();
},
},
[
m('label.label', 'Imię'),
m('input.input[type=text][placeholder=Imię]', {
oninput: function (e) {
User.current.firstName = e.target.value;
},
value: User.current.firstName,
}),
m('label.label', 'Nazwisko'),
m('input.input[placeholder=Nazwisko]', {
oninput: function (e) {
User.current.lastName = e.target.value;
},
value: User.current.lastName,
}),
m('button.button[type=submit]', 'Zapisz'),
]
);
},
};
Dodaliśmy obsługę zdarzenia oninput
dla obu pól tekstowych, co powoduje aktualizację właściwości User.current.firstName
i User.current.lastName
w trakcie wpisywania.
Ponadto zadeklarowaliśmy, że metoda User.save
powinna być wywoływana po kliknięciu przycisku "Zapisz". Zaimplementujmy teraz tę metodę:
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users',
withCredentials: true,
})
.then(function (result) {
User.list = result.data;
});
},
current: {},
load: function (id) {
return m
.request({
method: 'GET',
url: 'https://mithril-rem.fly.dev/api/users/' + id,
withCredentials: true,
})
.then(function (result) {
User.current = result;
});
},
save: function () {
return m.request({
method: 'PUT',
url: 'https://mithril-rem.fly.dev/api/users/' + User.current.id,
body: User.current,
withCredentials: true,
});
},
};
module.exports = User;
W metodzie save
użyliśmy metody HTTP PUT
, aby poinformować serwer, że wysyłamy dane w celu aktualizacji istniejącego rekordu.
Teraz spróbuj edytować imię użytkownika w aplikacji. Po zapisaniu zmian powinieneś zobaczyć, że zmiana została odzwierciedlona na liście użytkowników.
Obecnie powrót do listy użytkowników jest możliwy tylko za pomocą przycisku "Wstecz" w przeglądarce. Idealnym rozwiązaniem byłoby posiadanie menu, a ogólniej, szablonu, w którym moglibyśmy umieścić elementy interfejsu użytkownika dostępne globalnie.
Utwórzmy plik src/views/Layout.js
:
// src/views/Layout.js
var m = require('mithril');
module.exports = {
view: function (vnode) {
return m('main.layout', [
m('nav.menu', [m(m.route.Link, { href: '/list' }, 'Użytkownicy')]),
m('section', vnode.children),
]);
},
};
Ten komponent jest stosunkowo prosty i zawiera element <nav>
z linkiem do listy użytkowników. Podobnie jak w przypadku linków /edit
, ten link wykorzystuje m.route.Link
do stworzenia linku obsługującego routing.
Zauważ, że znajduje się tam również element <section>
zawierający vnode.children
. vnode
jest referencją do wirtualnego węzła (vnode), który reprezentuje instancję komponentu Layout (czyli vnode zwrócony przez wywołanie m(Layout)
). Dlatego vnode.children
odnosi się do wszystkich węzłów potomnych danego vnode.
Zaktualizujmy jeszcze raz style:
/* styles.css */
body,
.input,
.button {
font: normal 16px Verdana;
margin: 0;
}
.layout {
margin: 10px auto;
max-width: 1000px;
}
.menu {
margin: 0 0 30px;
}
.user-list {
list-style: none;
margin: 0 0 10px;
padding: 0;
}
.user-list-item {
background: #fafafa;
border: 1px solid #ddd;
color: #333;
display: block;
margin: 0 0 1px;
padding: 8px 15px;
text-decoration: none;
}
.user-list-item:hover {
text-decoration: underline;
}
.label {
display: block;
margin: 0 0 5px;
}
.input {
border: 1px solid #ddd;
border-radius: 3px;
box-sizing: border-box;
display: block;
margin: 0 0 10px;
padding: 10px 15px;
width: 100%;
}
.button {
background: #eee;
border: 1px solid #ddd;
border-radius: 3px;
color: #333;
display: inline-block;
margin: 0 0 10px;
padding: 10px 15px;
text-decoration: none;
}
.button:hover {
background: #e8e8e8;
}
Zmodyfikujmy konfigurację routera w pliku src/index.js
, aby uwzględnić nasz szablon:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
var UserForm = require('./views/UserForm');
var Layout = require('./views/Layout');
m.route(document.body, '/list', {
'/list': {
render: function () {
return m(Layout, m(UserList));
},
},
'/edit/:id': {
render: function (vnode) {
return m(Layout, m(UserForm, vnode.attrs));
},
},
});
Każdy komponent został zastąpiony przez RouteResolver (czyli obiekt z metodą render
). Metody render
można pisać w taki sam sposób, jak zwykłe widoki komponentów, poprzez zagnieżdżanie wywołań m()
.
Warto zwrócić uwagę na możliwość użycia komponentów zamiast selektora CSS w wywołaniu m()
. Tutaj, w trasie /list
, mamy m(Layout, m(UserList))
. Oznacza to, że istnieje główny vnode, który reprezentuje instancję Layout
, a jego jedynym elementem potomnym jest vnode UserList
.
W trasie /edit/:id
istnieje również argument vnode
, który przekazuje parametry trasy do komponentu UserForm
. Zatem, jeśli adres URL to /edit/1
, to vnode.attrs
przyjmuje wartość {id: 1}
, a wyrażenie m(UserForm, vnode.attrs)
jest równoważne z m(UserForm, {id: 1})
. Odpowiednikiem w JSX jest <UserForm id={vnode.attrs.id} />
.
Odśwież stronę w przeglądarce, a teraz zobaczysz globalną nawigację na każdej stronie aplikacji.
To kończy ten samouczek.
W tym samouczku przeszliśmy przez proces tworzenia bardzo prostej aplikacji, w której możemy wyświetlać listę użytkowników pobraną z serwera i edytować ich dane. Zachęcamy do samodzielnej implementacji funkcjonalności tworzenia i usuwania użytkowników jako dodatkowe ćwiczenie.
Jeśli chcesz zobaczyć więcej przykładów kodu Mithril.js, sprawdź stronę przykłady. Jeśli masz pytania, możesz zajrzeć na czat Mithril.js.