m(selector, attributes, children)
Beschreibung
Erstellt ein HTML-Element in einer Mithril.js-Darstellung.
m('div.foo', { style: { color: 'red' } }, 'hello');
// wird zu folgendem HTML gerendert:
// <div class="foo" style="color: red">hello</div>
Sie können auch eine HTML-ähnliche Syntax, genannt JSX, verwenden, indem Sie Babel verwenden, um sie in äquivalente Hyperscript-Aufrufe zu konvertieren. Dies entspricht dem oben genannten Beispiel.
<div class="foo" style="color: red">
hello
</div>
Signatur
vnode = m(selector, attrs, children)
Argument | Typ | Erforderlich | Beschreibung |
---|---|---|---|
selector | String|Object|Function | Ja | Ein CSS-Selektor oder eine Komponente |
attrs | Object | Nein | HTML-Attribute oder Element-Eigenschaften |
children | Array<Vnode>|String|Number|Boolean | Nein | Kindknoten (VNodes). Kann als Splat-Argumente übergeben werden |
returns | Vnode | Ein VNode |
Funktionsweise
Mithril.js bietet eine Hyperscript-Funktion m()
, die es ermöglicht, jede HTML-Struktur mit JavaScript-Syntax auszudrücken. Sie akzeptiert einen selector
(erforderlich), ein attrs
-Objekt (optional) und ein children
-Array (optional).
m('div', { id: 'box' }, 'hello');
// wird zu folgendem HTML gerendert:
// <div id="box">hello</div>
Die Funktion m()
gibt nicht direkt ein DOM-Element zurück. Stattdessen gibt sie einen virtuellen DOM-Knoten oder VNode zurück. Ein VNode ist ein JavaScript-Objekt, das das zu erstellende DOM-Element darstellt.
// ein VNode
var vnode = {
tag: 'div',
attrs: { id: 'box' },
children: [
/*...*/
],
};
Um einen VNode in ein tatsächliches DOM-Element zu transformieren, verwenden Sie die Funktion m.render()
:
m.render(document.body, m('br')); // fügt ein <br> in <body> ein
Das wiederholte Aufrufen von m.render()
erstellt den DOM-Baum nicht jedes Mal neu. Stattdessen nimmt jeder Aufruf nur dann Änderungen an einem DOM-Baum vor, wenn dies unbedingt erforderlich ist, um den virtuellen DOM-Baum widerzuspiegeln, der dem Aufruf übergeben wurde. Dieses Verhalten ist wünschenswert, da das Neuerstellen des DOM von Grund auf sehr aufwendig ist und Probleme wie den Verlust des Eingabefokus verursachen kann. Im Gegensatz dazu ist das Aktualisieren des DOM nur bei Bedarf vergleichsweise viel schneller und erleichtert die Wartung komplexer UIs, die mehrere User Stories verarbeiten.
Flexibilität
Die Funktion m()
ist sowohl polymorph als auch variadisch (veränderlich). Mit anderen Worten, sie ist sehr flexibel in Bezug auf die erwarteten Eingabeparameter:
// einfacher Tag
m('div'); // <div></div>
// Attribute und Kinder sind optional
m('a', { id: 'b' }); // <a id="b"></a>
m('span', 'hello'); // <span>hello</span>
// Element mit untergeordneten Knoten
m('ul', [
// <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world'), // <li>world</li>
]); // </ul>
// Array ist optional
m(
'ul', // <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world') // <li>world</li>
); // </ul>
CSS-Selektoren
Das erste Argument von m()
kann ein beliebiger CSS-Selektor sein, der ein HTML-Element beschreiben kann. Es akzeptiert alle gültigen CSS-Kombinationen der Syntax #
(ID), .
(Klasse) und []
(Attribut).
m('div#hello');
// <div id="hello"></div>
m('section.container');
// <section class="container"></section>
m('input[type=text][placeholder=Name]');
// <input type="text" placeholder="Name" />
m("a#exit.external[href='https://example.com']", 'Leave');
// <a id="exit" class="external" href="https://example.com">Leave</a>
Wenn Sie den Tag-Namen weglassen, nimmt Mithril.js an, dass es sich um ein div
-Tag handelt.
m('.box.box-bordered'); // <div class="box box-bordered"></div>
Es wird empfohlen, CSS-Selektoren für statische Attribute (d. h. Attribute, deren Wert sich nicht ändert) zu verwenden und ein Attribut-Objekt für dynamische Attributwerte zu übergeben.
var currentURL = '/';
m(
'a.link[href=/]',
{
class: currentURL === '/' ? 'selected' : '',
},
'Home'
);
// wird zu folgendem HTML gerendert:
// <a href="/" class="link selected">Home</a>
Attribute, die als zweites Argument übergeben werden
Sie können Attribute, Eigenschaften, Ereignisse und Lifecycle-Hooks im zweiten, optionalen Argument übergeben (siehe die nächsten Abschnitte für Details).
m("button", {
class: "my-button",
onclick: function() {/* ... */},
oncreate: function() {/* ... */}
})
Wenn der Wert eines Attributs null
oder undefined
ist, wird es so behandelt, als ob das Attribut nicht vorhanden wäre.
Wenn sowohl im ersten als auch im zweiten Argument von m()
Klassennamen angegeben sind, werden diese wie erwartet zusammengeführt. Wenn der Wert der Klasse im zweiten Argument null
oder undefined
ist, wird er ignoriert.
Wenn ein anderes Attribut sowohl im ersten als auch im zweiten Argument vorhanden ist, hat das zweite Vorrang, selbst wenn es null
oder undefined
ist.
DOM-Attribute
Mithril.js nutzt sowohl die JavaScript-API als auch die DOM-API (setAttribute
), um Attribute aufzulösen. Dies bedeutet, dass Sie beide Syntaxen verwenden können, um auf Attribute zu verweisen.
Zum Beispiel wird in der JavaScript-API das Attribut readonly
als element.readOnly
bezeichnet (beachten Sie die Großschreibung). In Mithril.js werden alle folgenden Varianten unterstützt:
m('input', { readonly: true }); // Kleinbuchstaben
m('input', { readOnly: true }); // Großschreibung
m('input[readonly]');
m('input[readOnly]');
Dies gilt auch für benutzerdefinierte Elemente. Zum Beispiel können Sie A-Frame innerhalb von Mithril.js problemlos verwenden!
m('a-scene', [
m('a-box', {
position: '-1 0.5 -3',
rotation: '0 45 0',
color: '#4CC3D9',
}),
m('a-sphere', {
position: '0 1.25 -5',
radius: '1.25',
color: '#EF2D5E',
}),
m('a-cylinder', {
position: '1 0.75 -3',
radius: '0.5',
height: '1.5',
color: '#FFC65D',
}),
m('a-plane', {
position: '0 0 -4',
rotation: '-90 0 0',
width: '4',
height: '4',
color: '#7BC8A4',
}),
m('a-sky', {
color: '#ECECEC',
}),
]);
Für benutzerdefinierte Elemente werden Eigenschaften nicht automatisch in Zeichenketten umgewandelt, falls es sich um Objekte, Zahlen oder andere Nicht-String-Werte handelt. Angenommen, Sie hätten ein benutzerdefiniertes Element my-special-element
, das eine Array-Getter/Setter-Eigenschaft elem.whitelist
hat, könnten Sie Folgendes tun, und es würde wie erwartet funktionieren:
m('my-special-element', {
whitelist: [
'https://example.com',
'https://neverssl.com',
'https://google.com',
],
});
Wenn Sie Klassen oder IDs für diese Elemente haben, funktionieren die Kurzschreibweisen weiterhin wie erwartet. Um ein weiteres A-Frame-Beispiel heranzuziehen:
// Diese beiden sind äquivalent
m('a-entity#player');
m('a-entity', { id: 'player' });
Beachten Sie, dass alle Eigenschaften mit spezieller Semantik, wie z. B. Lifecycle-Attribute, onevent
-Handler, key
s, class
und style
, weiterhin auf die gleiche Weise behandelt werden wie bei normalen HTML-Elementen.
Style-Attribut
Mithril.js unterstützt sowohl Zeichenketten als auch Objekte als gültige style
-Werte. Mit anderen Worten, alle folgenden Varianten werden unterstützt:
m('div', { style: 'background:red;' });
m('div', { style: { background: 'red' } });
m('div[style=background:red]');
Die Verwendung einer Zeichenkette für style
würde alle Inline-Styles im Element überschreiben, wenn dieses neu gezeichnet wird, und nicht nur die CSS-Regeln, deren Werte sich geändert haben.
Sie können sowohl CSS-Eigenschaftsnamen mit Bindestrich (wie background-color
) als auch DOM-style
-Eigenschaftsnamen in Camel Case (wie backgroundColor
) verwenden. Sie können auch CSS-benutzerdefinierte Eigenschaften definieren, falls Ihr Browser diese unterstützt.
Mithril.js versucht nicht, Zahlwerten Einheiten hinzuzufügen. Es wandelt sie einfach in Zeichenketten um.
Ereignisse
Mithril.js unterstützt die Ereignisbehandlung für alle DOM-Ereignisse, einschließlich Ereignisse, deren Spezifikationen keine on${event}
-Eigenschaft definieren, wie z. B. touchstart
.
function doSomething(e) {
console.log(e);
}
m('div', { onclick: doSomething });
Mithril.js akzeptiert Funktionen und EventListener-Objekte. Das Folgende funktioniert also auch:
var clickListener = {
handleEvent: function (e) {
console.log(e);
},
};
m('div', { onclick: clickListener });
Standardmäßig löst ein Ereignis, das mit Hyperscript verknüpft ist, nach der Rückgabe Ihres Event-Callbacks automatisch ein automatisches Re-Rendering von Mithril.js aus (vorausgesetzt, Sie verwenden m.mount
oder m.route
anstelle von m.render
direkt). Sie können das automatische Re-Rendering speziell für ein einzelnes Ereignis deaktivieren, indem Sie e.redraw = false
dafür setzen:
m('div', {
onclick: function (e) {
// Automatisches Neuzeichnen verhindern
e.redraw = false;
},
});
Eigenschaften
Mithril.js unterstützt DOM-Funktionen, auf die über Eigenschaften wie selectedIndex
und value
von <select>
zugegriffen werden kann.
m('select', { selectedIndex: 0 }, [
m('option', 'Option A'),
m('option', 'Option B'),
]);
Komponenten
Komponenten ermöglichen es Ihnen, Logik in einer Einheit zu kapseln und sie so zu verwenden, als wäre sie ein Element. Sie sind die Basis für die Erstellung großer, skalierbarer Anwendungen.
Eine Komponente ist ein beliebiges JavaScript-Objekt, das eine view
-Methode enthält. Um eine Komponente zu verwenden, übergeben Sie die Komponente als erstes Argument an m()
, anstatt einen CSS-Selektor-String zu übergeben. Sie können Argumente an die Komponente übergeben, indem Sie Attribute und Kinder definieren, wie im folgenden Beispiel gezeigt.
// eine Komponente definieren
var Greeter = {
view: function (vnode) {
return m('div', vnode.attrs, ['Hello ', vnode.children]);
},
};
// sie verwenden
m(Greeter, { style: 'color:red;' }, 'world');
// wird zu folgendem HTML gerendert:
// <div style="color:red;">Hello world</div>
Um mehr über Komponenten zu erfahren, siehe die Seite Komponenten.
Lifecycle-Methoden
VNodes und Komponenten können Lifecycle-Methoden (auch bekannt als Hooks) haben, die zu verschiedenen Zeitpunkten während der Lebensdauer eines DOM-Elements aufgerufen werden. Die von Mithril.js unterstützten Lifecycle-Methoden sind: oninit
, oncreate
, onupdate
, onbeforeremove
, onremove
und onbeforeupdate
.
Lifecycle-Methoden werden auf die gleiche Weise definiert wie DOM-Ereignisbehandler, erhalten aber den VNode als Argument anstelle eines Event-Objekts:
function initialize(vnode) {
console.log(vnode);
}
m('div', { oninit: initialize });
Hook | Beschreibung |
---|---|
oninit(vnode) | Wird ausgeführt, bevor ein VNode in ein echtes DOM-Element gerendert wird. |
oncreate(vnode) | Wird ausgeführt, nachdem ein VNode an das DOM angehängt wurde. |
onupdate(vnode) | Wird jedes Mal ausgeführt, wenn ein Neuzeichnen erfolgt, während das DOM-Element an das Dokument angehängt ist. |
onbeforeremove(vnode) | Wird ausgeführt, bevor ein DOM-Element aus dem Dokument entfernt wird. Wenn ein Promise zurückgegeben wird, löst Mithril.js das DOM-Element erst nach Abschluss des Promise ab. Diese Methode wird nur für das Element ausgelöst, das von seinem übergeordneten DOM-Element getrennt wird, nicht aber für seine untergeordneten Elemente. |
onremove(vnode) | Wird ausgeführt, nachdem ein DOM-Element aus dem Dokument entfernt wurde. Wenn ein onbeforeremove -Hook definiert ist, wird onremove aufgerufen, nachdem done aufgerufen wurde. Diese Methode wird für das Element ausgelöst, das von seinem übergeordneten Element getrennt wird, und für alle seine Kinder. |
onbeforeupdate(vnode, old) | Wird vor onupdate ausgeführt und verhindert eine Differenzberechnung für das Element und alle seine Kinder, wenn es false zurückgibt. |
Um mehr über Lifecycle-Methoden zu erfahren, siehe die Seite Lifecycle-Methoden.
Keys
VNodes in einer Liste können ein spezielles Attribut namens key
haben, das verwendet werden kann, um die Identität des DOM-Elements zu verwalten, wenn sich die Modelldaten ändern, die die VNode-Liste generieren.
Typischerweise sollte key
das eindeutige Kennungsfeld der Objekte im Datenarray sein.
var users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Mary' },
];
function userInputs(users) {
return users.map(function (u) {
return m('input', { key: u.id }, u.name);
});
}
m.render(document.body, userInputs(users));
Ein Key bedeutet, dass, wenn das users
-Array gemischt und die Ansicht neu gerendert wird, die Eingabefelder in der exakt gleichen Reihenfolge angeordnet werden, um den korrekten Fokus und DOM-Status beizubehalten.
Um mehr über Keys zu erfahren, siehe die Seite Keys.
SVG und MathML
Mithril.js bietet vollständige Unterstützung für SVG. Xlink wird ebenfalls unterstützt, muss aber im Gegensatz zu den Pre-v1.0-Versionen von Mithril.js den Namespace explizit definiert haben:
m('svg', [m("image[xlink:href='image.gif']")]);
MathML wird ebenfalls vollständig unterstützt.
Vorlagen dynamisch gestalten
Da verschachtelte VNodes nur einfache JavaScript-Ausdrücke sind, können Sie einfach JavaScript-Funktionen verwenden, um diese zu manipulieren.
Dynamischer Text
var user = { name: 'John' };
m('.name', user.name); // <div class="name">John</div>
Schleifen
Verwenden Sie Array
-Methoden wie map
, um Listen von Daten zu durchlaufen.
var users = [{ name: 'John' }, { name: 'Mary' }];
m(
'ul',
users.map(function (u) {
// <ul>
return m('li', u.name); // <li>John</li>
// <li>Mary</li>
})
); // </ul>
// ES6+:
// m("ul", users.map(u =>
// m("li", u.name)
// ))
Bedingungen
Verwenden Sie den ternären Operator, um Inhalte bedingt in einer Ansicht festzulegen.
var isError = false;
m('div', isError ? 'An error occurred' : 'Saved'); // <div>Saved</div>
Sie können keine JavaScript-Anweisungen wie if
oder for
innerhalb von JavaScript-Ausdrücken verwenden. Es ist besser, diese Anweisungen ganz zu vermeiden und stattdessen ausschließlich die obigen Konstrukte zu verwenden, um die Struktur der Vorlagen linear und deklarativ zu halten.
Konvertieren von HTML
In Mithril.js ist wohlgeformtes HTML gültiges JSX. Es ist nur wenig Aufwand erforderlich, außer dem Kopieren und Einfügen, um eine unabhängig erstellte HTML-Datei in ein Projekt mit JSX zu integrieren.
Bei Verwendung von Hyperscript ist es notwendig, HTML in Hyperscript-Syntax zu konvertieren, bevor der Code ausgeführt werden kann. Um dies zu erleichtern, können Sie den HTML-zu-Mithril-Vorlagenkonverter verwenden.
Anti-Patterns vermeiden
Obwohl Mithril.js flexibel ist, sind einige Codemuster nicht empfehlenswert.
Dynamische Selektoren vermeiden
Verschiedene DOM-Elemente haben unterschiedliche Attribute und oft unterschiedliche Verhaltensweisen. Das Konfigurieren eines Selektors kann dazu führen, dass Implementierungsdetails einer Komponente nach außen dringen.
// VERMEIDEN
var BadInput = {
view: function (vnode) {
return m('div', [m('label'), m(vnode.attrs.type||'input')]);
},
};
Anstatt Selektoren dynamisch zu gestalten, wird empfohlen, jede gültige Möglichkeit explizit zu codieren oder den variablen Teil des Codes auszulagern.
// Expliziten Code bevorzugen
var BetterInput = {
view: function (vnode) {
return m('div', [m('label', vnode.attrs.title), m('input')]);
},
};
var BetterSelect = {
view: function (vnode) {
return m('div', [m('label', vnode.attrs.title), m('select')]);
},
};
// Variabilität auslagern bevorzugen
var BetterLabeledComponent = {
view: function (vnode) {
return m('div', [m('label', vnode.attrs.title), vnode.children]);
},
};
Vermeiden Sie das Erstellen von VNodes außerhalb von Ansichten
Wenn ein Neuzeichnen auf einen VNode trifft, der genau dem im vorherigen Render entspricht, wird dieser übersprungen und sein Inhalt wird nicht aktualisiert. Dies mag wie eine Möglichkeit zur Leistungsoptimierung erscheinen, sollte aber vermieden werden, da es dynamische Änderungen im Baum dieses Knotens verhindert - dies führt zu Nebeneffekten, wie z. B. das Fehlschlagen von Downstream-Lifecycle-Methoden beim Neuzeichnen. In diesem Sinne sind Mithril.js-VNodes unveränderlich: Neue VNodes werden mit alten verglichen; Mutationen an VNodes werden nicht beibehalten.
Die Komponentendokumentation enthält weitere Details und ein Beispiel für dieses Anti-Pattern.