m(selector, attributes, children)
Leírás
HTML elem reprezentációja Mithril.js nézetben.
m('div.foo', { style: { color: 'red' } }, 'hello');
// a következő HTML-t generálja:
// <div class="foo" style="color: red">hello</div>
HTML-szerű szintaxist is használhatsz, amelyet JSX-nek hívnak, a Babel segítségével átalakítva azt egyenértékű hyperscript hívásokká. Ez megegyezik a fentivel.
<div class="foo" style="color: red">
hello
</div>
Aláírás
vnode = m(selector, attrs, children)
Argumentum | Típus | Kötelező | Leírás |
---|---|---|---|
selector | String|Object|Function | Igen | Egy CSS szelector, vagy egy komponens. |
attrs | Object | Nem | HTML attribútumok vagy elem tulajdonságok. |
children | Array<Vnode>|String|Number|Boolean | Nem | Gyermek vnode-ok. Splat argumentumként is megadható. |
visszatér | Vnode | Egy vnode. |
Működés
A Mithril.js egy m()
hyperscript függvényt biztosít, mely lehetővé teszi bármilyen HTML struktúra JavaScript szintaxissal való leírását. Elfogad egy selector
stringet (kötelező), egy attrs
objektumot (opcionális) és egy children
tömböt (opcionális).
m('div', { id: 'box' }, 'hello');
// a következő HTML-t generálja:
// <div id="box">hello</div>
Az m()
függvény valójában nem DOM elemet ad vissza. Ehelyett egy virtuális DOM csomópontot, más néven vnode-ot ad vissza, amely egy JavaScript objektum, ami a létrehozandó DOM elemet reprezentálja.
// egy vnode
var vnode = {
tag: 'div',
attrs: { id: 'box' },
children: [
/*...*/
],
};
Ahhoz, hogy egy vnode-ot tényleges DOM elemmé alakítsunk, használjuk az m.render()
függvényt:
m.render(document.body, m('br')); // egy <br>-t helyez a <body>-ba
Az m.render()
többszöri meghívása nem hozza létre újra a DOM fát minden alkalommal a semmiből. Ehelyett minden hívás csak akkor módosít egy DOM fát, ha az feltétlenül szükséges a hívásba átadott virtuális DOM fa tükrözéséhez. Ez a viselkedés kívánatos, mert a DOM újbóli létrehozása a nulláról nagyon költséges, és olyan problémákat okozhat, mint például a beviteli fókusz elvesztése. Ezzel szemben a DOM csak a szükséges helyeken történő frissítése összehasonlítva sokkal gyorsabb, és megkönnyíti a komplex felhasználói felületek karbantartását, amelyek több felhasználói történetet kezelnek.
Flexibilitás
Az m()
függvény egyszerre polimorf és variadikus (változó argumentumszámú). Más szavakkal, nagyon rugalmas abban, hogy mit vár bemeneti paraméterként:
// egyszerű tag
m('div'); // <div></div>
// az attribútumok és a gyermekek opcionálisak
m('a', { id: 'b' }); // <a id="b"></a>
m('span', 'hello'); // <span>hello</span>
// tag gyermek csomópontokkal
m('ul', [
// <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world'), // <li>world</li>
]); // </ul>
// a tömb opcionális
m(
'ul', // <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world') // <li>world</li>
); // </ul>
CSS kiválasztók
Az m()
első argumentuma bármilyen CSS szelector lehet, amely leírhat egy HTML elemet. Elfogad bármilyen érvényes CSS kombinációt a #
(id), .
(class) és []
(attribútum) szintaxisából.
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>
Ha kihagyod a tag nevet, a Mithril.js feltételezi a div
taget.
m('.box.box-bordered'); // <div class="box box-bordered"></div>
Általában ajánlott CSS szelectorokat használni a statikus attribútumokhoz (azaz azokhoz az attribútumokhoz, amelyek értéke nem változik), és egy attribútum objektumot átadni a dinamikus attribútum értékekhez.
var currentURL = '/';
m(
'a.link[href=/]',
{
class: currentURL === '/' ? 'selected' : '',
},
'Home'
);
// a következő HTML-t generálja:
// <a href="/" class="link selected">Home</a>
Második argumentumként átadott attribútumok
A második, opcionális argumentumban attribútumokat, tulajdonságokat, eseménykezelőket és lifecycle hook-okat adhatsz át (a részletekért lásd a következő szakaszokat).
m("button", {
class: "my-button",
onclick: function() {/* ... */},
oncreate: function() {/* ... */}
})
Ha egy ilyen attribútum értéke null
vagy undefined
, akkor úgy kezeljük, mintha az attribútum nem lenne jelen.
Ha vannak osztálynevek az m()
első és második argumentumában is, akkor azok összevonásra kerülnek, ahogy az várható. Ha az osztály értéke a második argumentumban null
vagy undefined
, akkor az figyelmen kívül lesz hagyva.
Ha egy másik attribútum jelen van az első és a második argumentumban is, akkor a második élvez elsőbbséget, még akkor is, ha az null
vagy undefined
.
DOM tulajdonságok
A Mithril.js az attribútumok feloldásához a JavaScript API-t és a DOM API-t (setAttribute
) is használja. Ez azt jelenti, hogy mindkét szintaxist használhatod az attribútumokra való hivatkozáshoz.
Például a JavaScript API-ban a readonly
attribútum neve element.readOnly
(figyeld meg a nagybetűt). A Mithril.js-ben a következők mindegyike támogatott:
m('input', { readonly: true }); // kisbetűs
m('input', { readOnly: true }); // nagybetűs
m('input[readonly]');
m('input[readOnly]');
Ez még az egyéni elemeket is magában foglalja. Például használhatod az A-Frame-et a Mithril.js-en belül, probléma nélkül!
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',
}),
]);
Egyéni elemek esetén nem automatikusan string-esíti a tulajdonságokat, arra az esetre, ha azok objektumok, számok vagy valamilyen más nem-string érték. Tehát feltételezve, hogy van egy my-special-element
egyéni elemed, amely rendelkezik egy elem.whitelist
tömb getter/setter tulajdonsággal, akkor ezt megteheted, és úgy fog működni, ahogy várnád:
m('my-special-element', {
whitelist: [
'https://example.com',
'https://neverssl.com',
'https://google.com',
],
});
Ha vannak osztályaid vagy ID-id ezekhez az elemekhez, akkor a rövidítések továbbra is úgy működnek, ahogy várnád. Egy másik A-Frame példát véve:
// Ez a kettő egyenértékű
m('a-entity#player');
m('a-entity', { id: 'player' });
Ne feledd, hogy minden olyan tulajdonság, amely mágikus szemantikával rendelkezik, mint például a lifecycle attribútumok, az onevent
kezelők, a key
-ek, a class
és a style
, továbbra is ugyanúgy lesznek kezelve, mint a normál HTML elemek esetében.
Stílus attribútum
A Mithril.js támogatja a stringeket és az objektumokat is érvényes style
értékekként. Más szavakkal, a következők mindegyike támogatott:
m('div', { style: 'background:red;' });
m('div', { style: { background: 'red' } });
m('div[style=background:red]');
Ha stringet használunk style
-ként, az felülírja az elem összes inline stílusát az újrarajzoláskor, nem csak a megváltozott CSS szabályokat.
Használhatsz kötőjeles CSS tulajdonságneveket (mint például background-color
) és camel cased DOM style
tulajdonságneveket (mint például backgroundColor
). Meghatározhatsz CSS egyéni tulajdonságokat is, ha a böngésződ támogatja azokat.
A Mithril.js nem kísérli meg mértékegységeket hozzáadni a számértékekhez. Egyszerűen string-esíti azokat.
Eseménykezelés
A Mithril.js támogatja az eseménykezelő kötést az összes DOM eseményhez, beleértve azokat az eseményeket is, amelyeknek a specifikációi nem definiálnak on${event}
tulajdonságot, mint például a touchstart
.
function doSomething(e) {
console.log(e);
}
m('div', { onclick: doSomething });
A Mithril.js elfogad függvényeket és EventListener objektumokat is. Tehát ez is működni fog:
var clickListener = {
handleEvent: function (e) {
console.log(e);
},
};
m('div', { onclick: clickListener });
Alapértelmezés szerint, amikor egy hyperscripttel csatolt esemény kiváltódik, az kiváltja a Mithril.js automatikus újrarajzolását az eseménykezelő visszatérése után (feltételezve, hogy m.mount
-ot vagy m.route
-ot használsz közvetlenül az m.render
helyett). Letilthatod az automatikus újrarajzolást kifejezetten egyetlen eseményhez azáltal, hogy beállítod az e.redraw = false
-t rajta:
m('div', {
onclick: function (e) {
// Megakadályozza az automatikus újrarajzolást
e.redraw = false;
},
});
Elemtulajdonságok
A Mithril.js támogatja a DOM funkcionalitást, amely tulajdonságokon keresztül érhető el, mint például a <select>
selectedIndex
és value
tulajdonságai.
m('select', { selectedIndex: 0 }, [
m('option', 'Option A'),
m('option', 'Option B'),
]);
Összetevők
A Komponensek lehetővé teszik a logika egységbe zárását, így úgy használhatod őket, mintha elemek lennének. Ezek az alapjai a nagy, skálázható alkalmazások készítésének.
A komponens bármilyen JavaScript objektum, amely tartalmaz egy view
metódust. Egy komponens használatához add át a komponenst az m()
első argumentumaként ahelyett, hogy egy CSS szelector stringet adnál át. Argumentumokat adhatsz át a komponensnek attribútumok és gyermekek definiálásával, ahogy az az alábbi példában látható.
// definiál egy komponenst
var Greeter = {
view: function (vnode) {
return m('div', vnode.attrs, ['Hello ', vnode.children]);
},
};
// használja
m(Greeter, { style: 'color:red;' }, 'world');
// a következő HTML-t rendereli:
// <div style="color:red;">Hello world</div>
Ha többet szeretnél megtudni a komponensekről, nézd meg a komponensek oldalt.
Életciklus metódusok
A vnode-ok és a komponensek rendelkezhetnek lifecycle metódusokkal (más néven hook-okkal), melyek a DOM elem életciklusa során különböző pontokon futnak le. A Mithril.js által támogatott lifecycle metódusok a következők: oninit
, oncreate
, onupdate
, onbeforeremove
, onremove
és onbeforeupdate
.
A lifecycle metódusok ugyanúgy vannak definiálva, mint a DOM eseménykezelők, de egy Event objektum helyett a vnode-ot kapják argumentumként:
function initialize(vnode) {
console.log(vnode);
}
m('div', { oninit: initialize });
Hook | Leírás |
---|---|
oninit(vnode) | Akkor fut le, mielőtt egy vnode valódi DOM elemmé renderelődik. |
oncreate(vnode) | Akkor fut le, miután egy vnode hozzá lett fűzve a DOM-hoz. |
onupdate(vnode) | Akkor fut le minden alkalommal, amikor egy újrarajzolás történik, miközben a DOM elem a dokumentumhoz van csatolva. |
onbeforeremove(vnode) | Akkor fut le, mielőtt egy DOM elem eltávolításra kerülne a dokumentumból. Ha egy Promise kerül visszaadásra, a Mithril.js csak a promise befejezése után választja le a DOM elemet. Ez a metódus csak azon az elemen kerül kiváltásra, amely le van választva a szülő DOM eleméről, de a gyermek elemein nem. |
onremove(vnode) | Akkor fut le, mielőtt egy DOM elem eltávolításra kerülne a dokumentumból. Ha egy onbeforeremove hook van definiálva, az onremove a done meghívása után kerül meghívásra. Ez a metódus azon az elemen kerül kiváltásra, amely le van választva a szülő eleméről, és az összes gyermekén. |
onbeforeupdate(vnode, old) | Akkor fut le az onupdate előtt, és ha false -ot ad vissza, akkor megakadályozza az elem és az összes gyermeke diff-jét. |
Ha többet szeretnél megtudni a lifecycle metódusokról, nézd meg a lifecycle metódusok oldalt.
Kulcsok
A listában lévő vnode-ok rendelkezhetnek egy speciális attribútummal, amelyet key
-nek hívnak, és amely felhasználható a DOM elem identitásának kezelésére, amikor a vnode listát generáló modell adatok megváltoznak.
Általában a key
az adat tömbben lévő objektumok egyedi azonosító mezője kell, hogy legyen.
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));
A key megléte azt jelenti, hogy ha a users
tömb megkeveredik, és a nézet újra renderelődik, akkor a bemeneti mezők pontosan ugyanabban a sorrendben lesznek megkeverve, megőrizve a helyes fókuszt és a DOM állapotot.
Ha többet szeretnél megtudni a key-ekről, nézd meg a key-ek oldalt.
SVG és MathML támogatás
A Mithril.js teljes mértékben támogatja az SVG-t. A Mithril.js korábbi verzióitól eltérően az Xlink is támogatott, de az névtérnek explicit módon definiálva kell lennie:
m('svg', [m("image[xlink:href='image.gif']")]);
A MathML is teljes mértékben támogatott.
Dinamikus sablonok
Mivel a beágyazott vnode-ok egyszerű JavaScript kifejezések, könnyen használhatod a JavaScript lehetőségeit a manipulálásukhoz.
Dinamikus tartalom
var user = { name: 'John' };
m('.name', user.name); // <div class="name">John</div>
Ciklusok használata
Használj Array
metódusokat, mint például a map
az adatok listáin való iteráláshoz.
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)
// ))
Feltételes kifejezések
Használd a ternary operátort a tartalom feltételes beállításához egy nézeten.
var isError = false;
m('div', isError ? 'An error occurred' : 'Saved'); // <div>Saved</div>
Nem használhatsz JavaScript utasításokat, mint például az if
vagy a for
a JavaScript kifejezéseken belül. Előnyösebb elkerülni ezeknek az utasításoknak a használatát teljesen, és ehelyett kizárólag a fenti konstrukciókat használni annak érdekében, hogy a sablonok szerkezete lineáris és deklaratív maradjon.
HTML átalakítása
A Mithril.js-ben a jól formázott HTML érvényes JSX. Kevés erőfeszítésre van szükség a másoláson és beillesztésen kívül ahhoz, hogy egy függetlenül előállított HTML fájlt integrálj egy JSX-et használó projektbe.
Hyperscript használatakor a HTML-t hyperscript szintaxisra kell konvertálni, mielőtt a kód futtatható lenne. Ennek megkönnyítése érdekében használhatod a HTML-to-Mithril-template konvertert.
Kerülendő minták
Bár a Mithril.js rugalmas, néhány kódmintát nem ajánlott használni:
Kerülendők a dinamikus kiválasztók
A különböző DOM elemeknek különböző attribútumaik és gyakran különböző viselkedéseik vannak. Ha egy szelector konfigurálhatóvá válik, az kiszivárogtathatja egy komponens implementációs részleteit.
// KERÜLD
var BadInput = {
view: function (vnode) {
return m('div', [m('label'), m(vnode.attrs.type||'input')]);
},
};
Ahelyett, hogy a szelectorokat dinamikussá tennéd, javasolt explicit módon kódolni az összes érvényes lehetőséget, vagy refaktorálni a kód változó részét.
// ELŐNYBEN RÉSZESÍTI az explicit kódot
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')]);
},
};
// ELŐNYBEN RÉSZESÍTI a változékonyság refaktorálását
var BetterLabeledComponent = {
view: function (vnode) {
return m('div', [m('label', vnode.attrs.title), vnode.children]);
},
};
Kerülendő a vnode-ok nézeten kívüli létrehozása
Amikor egy újrarajzolás egy olyan vnode-dal találkozik, amely szigorúan egyenlő az előző renderelésben lévővel, akkor az ki lesz hagyva, és a tartalma nem lesz frissítve. Bár ez teljesítmény optimalizálási lehetőségnek tűnhet, el kell kerülni, mert megakadályozza a dinamikus változásokat az adott csomópont fájában - ez olyan mellékhatásokhoz vezet, mint például a downstream lifecycle metódusok sikertelen kiváltása újrarajzoláskor. Ebben az értelemben a Mithril.js vnode-ok megváltoztathatatlanok: az új vnode-okat a régiekhez hasonlítják; a vnode-ok módosításai nem maradnak meg.
A komponens dokumentációja további részleteket és egy példát tartalmaz erre az anti-mintára.