m(selector, attributes, children)
Description
Représente un élément HTML dans une vue Mithril.js.
m('div.foo', { style: { color: 'red' } }, 'hello');
// génère le HTML suivant :
// <div class="foo" style="color: red">hello</div>
Vous pouvez également utiliser une syntaxe de type HTML appelée JSX, en utilisant Babel pour la convertir en appels hyperscript équivalents. L'exemple ci-dessus est équivalent à :
<div class="foo" style="color: red">
hello
</div>
Signature
vnode = m(selector, attrs, children)
Argument | Type | Requis | Description |
---|---|---|---|
selector | String|Object|Function | Oui | Un sélecteur CSS ou un composant. |
attrs | Object | Non | Attributs HTML ou propriétés d'élément. |
children | Array<Vnode>|String|Number|Boolean | Non | Vnodes enfants. Peut être écrit avec la syntaxe splat arguments. |
returns | Vnode | Un vnode. |
Comment cela fonctionne
Mithril.js fournit une fonction hyperscript m()
, qui permet d'exprimer n'importe quelle structure HTML en utilisant la syntaxe JavaScript. Elle accepte une chaîne selector
(obligatoire), un objet attrs
(facultatif) et un tableau children
(facultatif).
m('div', { id: 'box' }, 'hello');
// génère le HTML suivant :
// <div id="box">hello</div>
La fonction m()
ne renvoie pas directement un élément DOM. Elle renvoie plutôt un nœud DOM virtuel, ou vnode, qui est un objet JavaScript représentant l'élément DOM à créer.
// un vnode
var vnode = {
tag: 'div',
attrs: { id: 'box' },
children: [
/*...*/
],
};
Pour transformer un vnode en un élément DOM réel, utilisez la fonction m.render()
:
m.render(document.body, m('br')); // insère un <br> dans <body>
Appeler m.render()
plusieurs fois ne recrée jamais l'arborescence DOM entièrement à chaque appel. Au lieu de cela, chaque appel ne modifiera l'arborescence DOM que s'il est absolument nécessaire de refléter l'arborescence DOM virtuelle transmise à l'appel. Ce comportement est souhaitable car recréer le DOM à partir de zéro est très coûteux et entraîne des problèmes tels que la perte de focus dans les champs de saisie, entre autres. En revanche, la mise à jour du DOM uniquement lorsque cela est nécessaire est comparativement beaucoup plus rapide et facilite la maintenance d'interfaces utilisateur complexes qui gèrent plusieurs scénarios utilisateur.
Flexibilité
La fonction m()
est à la fois polymorphe et variadique, c'est-à-dire qu'elle peut accepter différents types d'arguments et un nombre variable d'arguments. En d'autres termes, elle est très flexible quant à ce qu'elle attend comme paramètres d'entrée :
// balise simple
m('div'); // <div></div>
// les attributs et les enfants sont optionnels
m('a', { id: 'b' }); // <a id="b"></a>
m('span', 'hello'); // <span>hello</span>
// balise avec des éléments enfants
m('ul', [
// <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world'), // <li>world</li>
]); // </ul>
// le tableau est facultatif
m(
'ul', // <ul>
m('li', 'hello'), // <li>hello</li>
m('li', 'world') // <li>world</li>
); // </ul>
Sélecteurs CSS
Le premier argument de m()
peut être n'importe quel sélecteur CSS qui peut décrire un élément HTML. Il accepte toutes les combinaisons CSS valides de syntaxe #
(id), .
(classe) et []
(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>
Si vous omettez le nom de la balise, Mithril.js suppose une balise div
.
m('.box.box-bordered'); // <div class="box box-bordered"></div>
Il est généralement recommandé d'utiliser des sélecteurs CSS pour les attributs statiques, c'est-à-dire ceux dont la valeur ne change pas. Pour les attributs dynamiques, il est préférable de passer un objet d'attributs.
var currentURL = '/';
m(
'a.link[href=/]',
{
class: currentURL === '/' ? 'selected' : '',
},
'Home'
);
// génère le HTML suivant :
// <a href="/" class="link selected">Home</a>
Attributs passés comme deuxième argument
Vous pouvez passer des attributs HTML, des propriétés d'élément, des gestionnaires d'événements et des hooks de cycle de vie dans le deuxième argument facultatif (voir les sections suivantes pour plus de détails).
m("button", {
class: "my-button",
onclick: function() {/* ... */},
oncreate: function() {/* ... */}
})
Si la valeur d'un attribut est null
ou undefined
, elle est traitée comme si l'attribut était absent.
Si des noms de classe sont présents à la fois dans le premier et le deuxième argument de m()
, ils sont fusionnés comme prévu. Si la valeur de la classe dans le deuxième argument est null
ou undefined
, elle est ignorée.
Si un autre attribut est présent à la fois dans le premier et le deuxième argument, le deuxième a la priorité, même s'il est null
ou undefined
.
Attributs DOM
Mithril.js utilise à la fois l'API JavaScript et l'API DOM (setAttribute
) pour définir les attributs. Cela signifie que vous pouvez utiliser les deux syntaxes pour faire référence aux attributs.
Par exemple, dans l'API JavaScript, l'attribut readonly
est appelé element.readOnly
(notez la majuscule). Dans Mithril.js, tous les éléments suivants sont pris en charge :
m('input', { readonly: true }); // minuscule
m('input', { readOnly: true }); // majuscule
m('input[readonly]');
m('input[readOnly]');
Cela s'applique également aux éléments personnalisés. Par exemple, vous pouvez utiliser A-Frame avec Mithril.js, sans aucun problème !
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',
}),
]);
Pour les éléments personnalisés, Mithril.js ne convertit pas automatiquement les propriétés en chaînes, au cas où il s'agirait d'objets, de nombres ou d'une autre valeur non-chaîne. Donc, en supposant que vous ayez un élément personnalisé my-special-element
qui a une propriété getter/setter de tableau elem.whitelist
, vous pourriez faire ceci, et cela fonctionnerait comme prévu :
m('my-special-element', {
whitelist: [
'https://example.com',
'https://neverssl.com',
'https://google.com',
],
});
Si vous avez des classes ou des ID pour ces éléments, les raccourcis fonctionnent toujours comme prévu. Pour reprendre un autre exemple A-Frame :
// Ces deux éléments sont équivalents
m('a-entity#player');
m('a-entity', { id: 'player' });
Notez que toutes les propriétés avec une sémantique spéciale, comme les attributs de cycle de vie, les gestionnaires onevent
, les key
s, class
et style
, sont toujours traitées de la même manière que pour les éléments HTML normaux.
Attribut Style
Mithril.js prend en charge à la fois les chaînes et les objets comme valeurs style
valides. En d'autres termes, tous les éléments suivants sont pris en charge :
m('div', { style: 'background:red;' });
m('div', { style: { background: 'red' } });
m('div[style=background:red]');
Utiliser une chaîne comme valeur de style
écraserait tous les styles en ligne de l'élément lors d'un redessin, et non seulement les règles CSS dont les valeurs ont été modifiées.
Vous pouvez utiliser à la fois les noms de propriétés CSS avec trait d'union (comme background-color
) et les noms de propriétés style
DOM en camel case (comme backgroundColor
). Vous pouvez également définir des propriétés personnalisées CSS, si votre navigateur les prend en charge.
Mithril.js ne tente pas d'ajouter des unités aux valeurs numériques. Il les convertit simplement en chaînes.
Événements
Mithril.js prend en charge la liaison de gestionnaires pour tous les événements DOM, y compris les événements dont les spécifications ne définissent pas de propriété on${event}
, tels que touchstart
.
function doSomething(e) {
console.log(e);
}
m('div', { onclick: doSomething });
Mithril.js accepte les fonctions et les objets EventListener. Donc, cela fonctionnera également :
var clickListener = {
handleEvent: function (e) {
console.log(e);
},
};
m('div', { onclick: clickListener });
Par défaut, lorsqu'un événement est déclenché via hyperscript, Mithril.js effectue un redessin automatique après l'exécution de votre fonction de rappel (callback). Ceci est valable si vous utilisez m.mount
ou m.route
au lieu de m.render
directement. Vous pouvez désactiver le redessin automatique spécifiquement pour un seul événement en définissant e.redraw = false
:
m('div', {
onclick: function (e) {
// Empêcher le redessin automatique
e.redraw = false;
},
});
Propriétés
Mithril.js prend en charge les fonctionnalités DOM accessibles via des propriétés telles que les propriétés selectedIndex
et value
de <select>
.
m('select', { selectedIndex: 0 }, [
m('option', 'Option A'),
m('option', 'Option B'),
]);
Composants
Les composants vous permettent d'encapsuler la logique dans une unité et de l'utiliser comme s'il s'agissait d'un élément. Ils constituent la base pour la création d'applications vastes et évolutives.
Un composant est tout objet JavaScript qui contient une méthode view
. Pour utiliser un composant, passez le composant comme premier argument à m()
au lieu de passer une chaîne de sélecteur CSS. Vous pouvez passer des arguments au composant en définissant des attributs et des enfants, comme indiqué dans l'exemple ci-dessous.
// définir un composant
var Greeter = {
view: function (vnode) {
return m('div', vnode.attrs, ['Hello ', vnode.children]);
},
};
// l'utiliser
m(Greeter, { style: 'color:red;' }, 'world');
// génère le HTML suivant :
// <div style="color:red;">Hello world</div>
Pour en savoir plus sur les composants, consultez la page des composants.
Méthodes de cycle de vie
Les vnodes et les composants peuvent avoir des méthodes de cycle de vie (également appelées hooks), qui sont appelées à différents moments pendant la durée de vie d'un élément DOM. Les méthodes de cycle de vie prises en charge par Mithril.js sont : oninit
, oncreate
, onupdate
, onbeforeremove
, onremove
et onbeforeupdate
.
Les méthodes de cycle de vie sont définies de la même manière que les gestionnaires d'événements DOM, mais reçoivent le vnode comme argument, au lieu d'un objet Event :
function initialize(vnode) {
console.log(vnode);
}
m('div', { oninit: initialize });
Hook | Description |
---|---|
oninit(vnode) | Est appelé avant qu'un vnode soit rendu en tant qu'élément DOM réel. |
oncreate(vnode) | S'exécute après qu'un vnode est ajouté au DOM. |
onupdate(vnode) | S'exécute chaque fois qu'un redessin a lieu pendant que l'élément DOM est attaché au document. |
onbeforeremove(vnode) | S'exécute avant qu'un élément DOM soit retiré du document. Si une Promise est renvoyée, Mithril.js ne détache l'élément DOM qu'une fois la promesse terminée. Cette méthode n'est déclenchée que sur l'élément qui est détaché de son élément DOM parent, mais pas sur ses éléments enfants. |
onremove(vnode) | S'exécute avant qu'un élément DOM soit retiré du document. Si un hook onbeforeremove est défini, onremove est appelé après l'appel de done . Cette méthode est déclenchée sur l'élément qui est détaché de son élément parent, et sur tous ses enfants. |
onbeforeupdate(vnode, old) | S'exécute avant onupdate et, s'il renvoie false , empêche une comparaison différentielle pour l'élément et tous ses enfants. |
Pour en savoir plus sur les méthodes de cycle de vie, consultez la page des méthodes de cycle de vie.
Keys
Les vnodes d'une liste peuvent avoir un attribut spécial appelé key
, qui peut être utilisé pour gérer l'identité de l'élément DOM lorsque les données du modèle qui génèrent les modifications de la liste de vnodes changent.
En général, key
doit être le champ d'identifiant unique des objets dans le tableau de données.
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));
L'utilisation d'une clé garantit que si le tableau users
est mélangé et que la vue est redessinée, les entrées seront réorganisées dans le même ordre, préservant ainsi l'état correct du focus et du DOM.
Pour en savoir plus sur les clés, consultez la page des clés.
SVG et MathML
Mithril.js prend pleinement en charge SVG. Xlink est également pris en charge, mais contrairement aux versions antérieures à la version 1.0 de Mithril.js, doit avoir l'espace de noms explicitement défini :
m('svg', [m("image[xlink:href='image.gif']")]);
MathML est également entièrement pris en charge.
Rendre les templates dynamiques
Étant donné que les vnodes imbriqués ne sont que des expressions JavaScript simples, vous pouvez simplement utiliser les fonctionnalités JavaScript pour les manipuler.
Texte dynamique
var user = { name: 'John' };
m('.name', user.name); // <div class="name">John</div>
Boucles
Utilisez des méthodes Array
telles que map
pour itérer sur des listes de données.
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)
// ))
Conditionnelles
Utilisez l'opérateur ternaire pour définir le contenu d'une vue de manière conditionnelle.
var isError = false;
m('div', isError ? 'An error occurred' : 'Saved'); // <div>Saved</div>
Vous ne pouvez pas utiliser d'instructions JavaScript telles que if
ou for
dans des expressions JavaScript. Il est préférable d'éviter complètement d'utiliser ces instructions et d'utiliser plutôt les constructions ci-dessus exclusivement afin de maintenir la structure des templates linéaire et déclarative.
Conversion de HTML
Dans Mithril.js, le HTML bien formé est un JSX valide. Peu d'efforts autres que le copier-coller sont nécessaires pour intégrer un fichier HTML produit indépendamment dans un projet utilisant JSX.
Lors de l'utilisation d'hyperscript, il est nécessaire de convertir HTML en syntaxe hyperscript avant que le code puisse être exécuté. Pour faciliter cela, vous pouvez utiliser le convertisseur HTML-vers-modèle-Mithril.
Éviter les anti-patterns
Malgré la flexibilité de Mithril.js, certains modèles de code sont déconseillés :
Éviter les sélecteurs dynamiques
Différents éléments DOM ont des attributs différents, et souvent des comportements différents. Rendre un sélecteur configurable peut exposer les détails d'implémentation d'un composant en dehors de son unité.
// À ÉVITER
var BadInput = {
view: function (vnode) {
return m('div', [m('label'), m(vnode.attrs.type || 'input')]);
},
};
Au lieu de rendre les sélecteurs dynamiques, vous êtes encouragé à coder explicitement chaque possibilité valide, ou à refactoriser la partie variable.
// PRÉFÉRER le code explicite
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')]);
},
};
// PRÉFÉRER refactoriser la variabilité
var BetterLabeledComponent = {
view: function (vnode) {
return m('div', [m('label', vnode.attrs.title), vnode.children]);
},
};
Éviter de créer des vnodes en dehors des méthodes de vue
Lorsqu'un nouveau rendu rencontre un vnode strictement identique à celui du rendu précédent, il est ignoré et son contenu n'est pas mis à jour. Bien que cela puisse sembler être une opportunité d'optimisation des performances, il convient de l'éviter car cela empêche les modifications dynamiques dans l'arborescence de ce nœud - cela conduit à des effets secondaires tels que l'échec du déclenchement des méthodes de cycle de vie en aval lors du redessin. En ce sens, les vnodes Mithril.js sont immuables : les nouveaux vnodes sont comparés aux anciens ; les modifications des vnodes ne persistent pas.
La documentation du composant contient plus de détails et un exemple de cet anti-modèle.