Einfache Anwendung
Lass uns eine einfache Anwendung entwickeln, die die wichtigsten Aspekte demonstriert, mit denen man bei der Verwendung von Mithril konfrontiert wird.
Ein interaktives Beispiel des Endergebnisses kann hier
Erstellen wir zunächst die Startdatei für die Anwendung. Erstelle eine Datei index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Meine Anwendung</title>
</head>
<body>
<script src="bin/app.js"></script>
</body>
</html>
Der Doctype <!doctype html>
deklariert, dass es sich um ein HTML5-Dokument handelt. Das erste charset
-Meta-Tag gibt die Zeichenkodierung des Dokuments an, und das viewport
-Meta-Tag bestimmt, wie mobile Browser die Seite skalieren sollen. Das title
-Tag enthält den Text, der im Browser-Tab für diese Anwendung angezeigt wird, und das script
-Tag gibt den Pfad zu der JavaScript-Datei an, die die Anwendung ausführt.
Es wäre möglich, die gesamte Anwendung in einer einzigen JavaScript-Datei zu erstellen, aber dies würde die Navigation in der Codebasis später erschweren. Stattdessen teilen wir den Code in Module auf und fügen diese Module zu einem Bundle bin/app.js
zusammen.
Es gibt viele Möglichkeiten, ein Bundler-Tool zu konfigurieren, aber die meisten werden über npm verteilt. Tatsächlich werden die meisten modernen JavaScript-Bibliotheken und -Tools auf diese Weise verteilt, einschließlich Mithril. Um npm zu installieren, installiere Node.js; npm wird automatisch damit installiert. Sobald du Node.js und npm installiert hast, öffne die Kommandozeile und führe diesen Befehl aus:
npm init -y
Wenn npm korrekt installiert ist, wird eine Datei package.json
erstellt. Diese Datei enthält ein Grundgerüst einer Projekt-Metadatendatei. Du kannst die Projekt- und Autoreninformationen in dieser Datei bearbeiten.
Um Mithril.js zu installieren, folge bitte den Anweisungen auf der Seite Installation. Sobald du ein Projektgerüst mit installiertem Mithril.js hast, können wir die Anwendung erstellen.
Beginnen wir mit der Erstellung eines Moduls zum Speichern unseres Status. Erstellen wir eine Datei namens src/models/User.js
:
// src/models/User.js
var User = {
list: [],
};
module.exports = User;
Lass uns nun Code hinzufügen, um Daten von einem Server zu laden. Um mit einem Server zu interagieren, können wir die Hilfsfunktion XHR von Mithril.js, m.request
, verwenden. Zuerst binden wir Mithril.js in das Modul ein:
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
};
module.exports = User;
Nennen wir sie nun loadList
, die einen XHR-Aufruf auslöst.
// src/models/User.js
var m = require('mithril');
var User = {
list: [],
loadList: function () {
// TODO: make XHR call
},
};
module.exports = User;
Dann können wir einen m.request
-Aufruf hinzufügen, um eine XHR-Anfrage zu stellen. Für dieses Tutorial werden wir XHR-Aufrufe an die REM (DEAD LINK, FIXME: https //rem-rest-api.herokuapp.com/) API durchführen, eine Mock-REST-API, die für schnelles Prototyping entwickelt wurde. Diese API gibt eine Liste von Benutzern vom API-Endpunkt GET https://mithril-rem.fly.dev/api/users
zurück. Verwenden wir m.request
, um eine XHR-Anfrage zu stellen und unsere Daten mit der Antwort dieses Endpunkts zu füllen.
Hinweis: Drittanbieter-Cookies müssen möglicherweise aktiviert sein, damit der REM-Endpunkt funktioniert.
// 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;
Die method
-Option ist eine HTTP-Methode. Um Daten vom Server abzurufen, ohne dabei Nebenwirkungen zu verursachen, müssen wir die GET
-Methode verwenden. Die url
ist die Adresse für den API-Endpunkt. Die Zeile withCredentials: true
gibt an, dass wir Cookies verwenden (was eine Voraussetzung für die REM-API ist).
Der m.request
-Aufruf gibt ein Promise zurück, das zu den Daten vom Endpunkt aufgelöst wird. Standardmäßig geht Mithril.js davon aus, dass der HTTP-Antworttext im JSON-Format vorliegt und analysiert ihn automatisch in ein JavaScript-Objekt oder -Array. Der Callback .then
wird ausgeführt, wenn die XHR-Anfrage abgeschlossen ist. In diesem Fall weist der Callback das Array result.data
User.list
zu.
Beachten Sie, dass wir auch eine return
-Anweisung in loadList
haben. Dies ist eine allgemein gute Vorgehensweise bei der Arbeit mit Promises, die es uns ermöglicht, weitere Callbacks zu registrieren, die nach Abschluss der XHR-Anfrage ausgeführt werden sollen.
Dieses einfache Modell macht zwei Elemente verfügbar: User.list
(ein Array von Benutzerobjekten) und User.loadList
(eine Methode, die User.list
mit Serverdaten füllt).
Lass uns nun ein View-Modul erstellen, damit wir Daten aus unserem User-Modellmodul anzeigen können.
Erstelle eine Datei namens src/views/UserList.js
. Zuerst importieren wir Mithril.js und unser Modell, da wir beide verwenden müssen:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
Als Nächstes erstellen wir eine Mithril.js-Komponente. Eine Komponente ist einfach ein Objekt mit einer view
-Methode:
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
view: function () {
// TODO add code here
},
};
Standardmäßig werden die Ansichten in Mithril.js mit hyperscript beschrieben. Hyperscript bietet eine kompakte Syntax, die für komplexe Tags natürlicher als HTML eingerückt werden kann, und da die Syntax nur JavaScript ist, ist es möglich, einen Großteil des JavaScript-Tooling-Ökosystems zu nutzen. Zum Beispiel:
- Du kannst Babel verwenden, um ES6+ für IE nach ES5 zu transpilieren und JSX (eine Inline-HTML-ähnliche Syntaxerweiterung) in entsprechende Hyperscript-Aufrufe zu transpilieren.
- Du kannst ESLint für einfaches Linting ohne spezielle Plugins verwenden.
- Du kannst Terser oder UglifyJS (nur ES5) verwenden, um deinen Code einfach zu minimieren.
- Du kannst Istanbul für die Codeabdeckung verwenden.
- Du kannst TypeScript für einfache Codeanalyse verwenden. (Es gibt von der Community unterstützte Typdefinitionen, sodass du keine eigenen erstellen musst.)
Lass uns mit Hyperscript beginnen und eine Liste von Elementen erstellen. Hyperscript ist die idiomatische Art, Mithril.js zu verwenden, aber JSX funktioniert ziemlich ähnlich.
// src/views/UserList.js
var m = require('mithril');
var User = require('../models/User');
module.exports = {
view: function () {
return m('.user-list');
},
};
Die Zeichenkette ".user-list"
stellt einen CSS-Selektor dar, und wie du erwarten würdest, stellt .user-list
eine Klasse dar. Wenn kein Tag angegeben ist, ist div
die Standardeinstellung. Diese Ansicht entspricht also <div class="user-list"></div>
.
Lass uns nun die Liste der Benutzer aus dem Modell referenzieren, das wir zuvor erstellt haben (User.list
), um Daten dynamisch zu durchlaufen:
// 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);
})
);
},
};
Da User.list
ein JavaScript-Array ist und Hyperscript-Ansichten nur JavaScript sind, können wir das Array mit der Methode .map
durchlaufen. Dies erstellt ein Array von VNodes, das eine Liste von div
s darstellt, die jeweils den Namen eines Benutzers enthalten.
Das Problem ist, dass wir die Funktion User.loadList
nie aufgerufen haben. Daher ist User.list
immer noch ein leeres Array, und diese Ansicht würde somit eine leere Seite rendern. Da wir möchten, dass User.loadList
aufgerufen wird, wenn wir diese Komponente rendern, können wir die Lebenszyklusmethoden lifecycle methods der Komponente nutzen:
// 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);
})
);
},
};
Beachte, dass wir der Komponente eine oninit
-Methode hinzugefügt haben, die auf User.loadList
verweist. Dies bedeutet, dass beim Initialisieren der Komponente User.loadList
aufgerufen wird, wodurch eine XHR-Anfrage ausgelöst wird. Wenn der Server eine Antwort zurückgibt, wird User.list
gefüllt.
Beachte auch, dass wir nicht oninit: User.loadList()
(mit Klammern am Ende) geschrieben haben. Der Unterschied besteht darin, dass oninit: User.loadList()
die Funktion einmal und sofort aufruft, aber oninit: User.loadList
diese Funktion nur aufruft, wenn die Komponente gerendert wird. Dies ist ein wichtiger Unterschied und eine häufige Falle für Entwickler, die neu in JavaScript sind: Das sofortige Aufrufen der Funktion bedeutet, dass die XHR-Anfrage ausgelöst wird, sobald der Quellcode ausgewertet wird, selbst wenn die Komponente nie gerendert wird. Wenn die Komponente jemals neu erstellt wird (durch Navigieren vor und zurück durch die Anwendung), wird die Funktion auch nicht wie erwartet erneut aufgerufen.
Lass uns die Ansicht aus der Einstiegspunktdatei rendern, die wir zuvor erstellt haben:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
m.mount(document.body, UserList);
Der Aufruf von m.mount
rendert die angegebene Komponente (UserList
) in ein DOM-Element (document.body
) und löscht alle zuvor vorhandenen DOM-Elemente. Wenn Sie die HTML-Datei in einem Browser öffnen, sollte nun eine Liste von Personennamen angezeigt werden.
Momentan sieht die Liste recht schlicht aus, da wir keine Stile definiert haben. Lass uns daher einige davon hinzufügen. Erstellen wir zuerst eine Datei namens styles.css
und fügen sie in die Datei index.html
ein:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Meine Anwendung</title>
<link href="styles.css" rel="stylesheet" />
</head>
<body>
<script src="bin/app.js"></script>
</body>
</html>
Jetzt können wir die UserList
-Komponente stylen:
.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;
}
Ein Neuladen des Browserfensters sollte nun einige gestaltete Elemente anzeigen.
Lass uns Routing zu unserer Anwendung hinzufügen.
Routing bedeutet, einen Bildschirm mit einer eindeutigen URL zu verknüpfen, um die Möglichkeit zu schaffen, von einer "Seite" zur anderen zu gelangen. Mithril.js wurde für Single Page Applications entwickelt, daher sind diese "Seiten" nicht unbedingt verschiedene HTML-Dateien im traditionellen Sinne des Wortes. Stattdessen behält das Routing in Single Page Applications dieselbe HTML-Datei während ihrer gesamten Lebensdauer bei, ändert aber den Zustand der Anwendung über JavaScript. Clientseitiges Routing hat den Vorteil, dass es das Aufblitzen leerer Bildschirme zwischen Seitenübergängen vermeidet und die Menge der vom Server heruntergeladenen Daten reduzieren kann, wenn es in Verbindung mit einer serviceorientierten Webarchitektur verwendet wird (d. h. eine Anwendung, die Daten als JSON herunterlädt, anstatt vorgerenderte Teile von ausführlichem HTML herunterzuladen).
Wir können Routing hinzufügen, indem wir den m.mount
-Aufruf in einen m.route
-Aufruf umwandeln:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
m.route(document.body, '/list', {
'/list': UserList,
});
Der Aufruf von m.route
gibt an, dass die Anwendung in document.body
gerendert wird. Das Argument "/list"
stellt die Standardroute dar. Das bedeutet, dass der Benutzer zu dieser Route umgeleitet wird, wenn er auf einer Route landet, die nicht existiert. Das Objekt {"/list": UserList}
deklariert eine Zuordnung der vorhandenen Routen und die Komponenten, zu denen jede Route aufgelöst wird.
Wenn du die Seite im Browser aktualisierst, sollte nun #!/list
an die URL angehängt werden, um anzuzeigen, dass das Routing funktioniert. Da diese Route UserList
rendert, sollten wir immer noch die Liste der Personen auf dem Bildschirm sehen wie zuvor.
Der #!
-Snippet wird als Hashbang bezeichnet und ist eine häufig verwendete Zeichenkette zum Implementieren von clientseitigem Routing. Es ist möglich, diese Zeichenkette über m.route.prefix
zu konfigurieren. Einige Konfigurationen erfordern unterstützende serverseitige Änderungen, daher werden wir für den Rest dieses Tutorials einfach weiterhin den Hashbang verwenden.
Lass uns unserer Anwendung eine weitere Route zum Bearbeiten von Benutzern hinzufügen. Lass uns zunächst ein Modul namens views/UserForm.js
erstellen:
// src/views/UserForm.js
module.exports = {
view: function () {
// TODO implement view
},
};
Dann können wir dieses neue Modul in src/index.js
importieren:
// src/index.js
var m = require('mithril');
var UserList = require('./views/UserList');
var UserForm = require('./views/UserForm');
m.route(document.body, '/list', {
'/list': UserList,
});
Und schließlich können wir eine Route erstellen, die darauf verweist:
// 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,
});
Beachten Sie, dass die neue Route ein :id
enthält. Dies ist ein Routenparameter; Sie können ihn als Wildcard betrachten; die Route /edit/1
würde zu UserForm
mit einer id
von "1"
aufgelöst. /edit/2
würde auch zu UserForm
aufgelöst, aber mit einer id
von "2"
. Und so weiter.
Lass uns die UserForm
-Komponente so implementieren, dass sie auf diese Routenparameter reagieren kann:
// src/views/UserForm.js
var m = require('mithril');
module.exports = {
view: function () {
return m('form', [
m('label.label', 'Vorname'),
m('input.input[type=text][placeholder=Vorname]'),
m('label.label', 'Nachname'),
m('input.input[placeholder=Nachname]'),
m('button.button[type=submit]', 'Speichern'),
]);
},
};
Und fügen wir styles.css
einige weitere Stile hinzu:
/* 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;
}
Im Moment unternimmt diese Komponente nichts, um auf Benutzerereignisse zu reagieren. Fügen wir unserem User
-Modell in src/models/User.js
etwas Code hinzu. So sieht der Code im Moment aus:
// 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;
Fügen wir Code hinzu, damit wir einen einzelnen Benutzer laden können:
// 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;
Beachte, dass wir eine User.current
-Eigenschaft und eine User.load(id)
-Methode hinzugefügt haben, die diese Eigenschaft füllt. Wir können nun die UserForm
-Ansicht mit dieser neuen Methode füllen:
// 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', 'Vorname'),
m('input.input[type=text][placeholder=Vorname]', {
value: User.current.firstName,
}),
m('label.label', 'Nachname'),
m('input.input[placeholder=Nachname]', { value: User.current.lastName }),
m('button.button[type=submit]', 'Speichern'),
]);
},
};
Ähnlich wie bei der UserList
-Komponente ruft die oninit
-Methode User.load()
auf. Erinnerst du dich, dass wir einen Routenparameter namens :id
in der Route "/edit/:id": UserForm
hatten? Der Routenparameter wird zu einem Attribut des VNodes der UserForm
-Komponente, sodass das Routing zu /edit/1
dazu führen würde, dass vnode.attrs.id
den Wert "1"
hat.
Lass uns nun die UserList
-Ansicht ändern, sodass wir von dort zu einem UserForm
navigieren können:
// 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
);
})
);
},
};
Hier haben wir den .user-list-item
-VNode durch einen m.route.Link
mit derselben Klasse und denselben Kindelementen ersetzt. Wir haben ein href
hinzugefügt, das auf die gewünschte Route verweist. Das bedeutet, dass ein Klick auf den Link den Teil der URL ändern würde, der nach dem Hashbang #!
kommt (wodurch die Route geändert wird, ohne die aktuelle HTML-Seite zu entladen). Hinter den Kulissen wird ein <a>
verwendet, um den Link zu implementieren, und es funktioniert einfach alles.
Wenn Sie die Seite im Browser aktualisieren, sollten Sie nun auf eine Person klicken und zu einem Formular gelangen können. Du solltest auch in der Lage sein, die Zurück-Taste im Browser zu drücken, um vom Formular zurück zur Liste der Personen zu gelangen.
Das Formular speichert beim Klicken auf "Speichern" noch nicht. Machen wir dieses Formular funktionsfähig:
// 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', 'Vorname'),
m('input.input[type=text][placeholder=Vorname]', {
oninput: function (e) {
User.current.firstName = e.target.value;
},
value: User.current.firstName,
}),
m('label.label', 'Nachname'),
m('input.input[placeholder=Nachname]', {
oninput: function (e) {
User.current.lastName = e.target.value;
},
value: User.current.lastName,
}),
m('button.button[type=submit]', 'Speichern'),
]
);
},
};
Wir haben oninput
-Event-Handler zu beiden Eingabefeldern hinzugefügt, die die Eigenschaften User.current.firstName
und User.current.lastName
aktualisieren, sobald ein Benutzer etwas eingibt.
Zusätzlich haben wir festgelegt, dass die User.save
-Methode aufgerufen wird, wenn die Schaltfläche "Speichern" betätigt wird. Implementieren wir diese Methode nun:
// 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;
In der save
-Methode verwenden wir die HTTP-Methode PUT
, um anzugeben, dass wir Daten auf dem Server aktualisieren oder neu anlegen.
Versuchen Sie nun, den Namen eines Benutzers in der Anwendung zu bearbeiten. Sobald Sie eine Änderung speichern, sollte diese in der Benutzerliste sichtbar sein.
Aktuell können wir nur über die Zurück-Taste des Browsers zur Benutzerliste navigieren. Idealerweise hätten wir ein Menü – oder allgemeiner ein Layout, in dem wir globale UI-Elemente unterbringen können.
Erstellen wir eine Datei 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' }, 'Benutzer')]),
m('section', vnode.children),
]);
},
};
Diese Komponente ist relativ einfach aufgebaut: Sie enthält ein <nav>
-Element mit einem Link zur Benutzerliste. Ähnlich wie bei den /edit
-Links verwendet dieser Link m.route.Link
, um einen routingfähigen Link zu erstellen.
Beachten Sie, dass es auch ein <section>
-Element gibt, das vnode.children
als Kindelemente enthält. vnode
ist eine Referenz auf den VNode, der eine Instanz der Layout-Komponente darstellt (d.h. der VNode, der von einem m(Layout)
-Aufruf zurückgegeben wird). Daher verweisen vnode.children
auf alle Kindknoten dieses VNodes.
Und aktualisieren wir die Stile noch einmal:
/* 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;
}
Ändern wir den Router in src/index.js
, um unser Layout einzubinden:
// 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));
},
},
});
Wir haben jede Komponente durch einen RouteResolver ersetzt, der im Grunde ein Objekt mit einer render
-Methode ist. Die render
-Methoden können wie gewöhnliche Komponentenansichten geschrieben werden, indem man m()
-Aufrufe verschachtelt.
Interessant ist, wie Komponenten anstelle eines Selektor-Strings in einem m()
-Aufruf verwendet werden können. Das bedeutet, dass es einen Root-VNode gibt, der eine Instanz von Layout
repräsentiert und einen UserList
-VNode als einziges Kindelement enthält.
Wenn die URL also /edit/1
lautet, dann ist vnode.attrs
in diesem Fall {id: 1}
. Somit entspricht m(UserForm, vnode.attrs)
dem Ausdruck m(UserForm, {id: 1})
. Der entsprechende JSX-Code wäre <UserForm id={vnode.attrs.id} />
.
Aktualisieren Sie die Seite im Browser und Sie sehen nun die globale Navigation auf jeder Seite der App.
Damit endet dieses Tutorial.
In diesem Tutorial haben wir eine sehr einfache Anwendung erstellt, mit der wir Benutzer von einem Server auflisten und einzeln bearbeiten können. Als zusätzliche Übung können Sie versuchen, die Funktionen zum Erstellen und Löschen von Benutzern selbst zu implementieren.
Weitere Beispiele für Mithril.js-Code finden Sie auf der Seite Beispiele. Bei Fragen können Sie gerne den Mithril.js-Chatraum besuchen.