Tags personnalisés

Exemple

Les tags personnalisés de Riot sont les blocs de construction des interfaces utilisateur. Il s’agit de la partie “Vue” de votre application. Commencons par un exemple de todo list mettant en avant les différentes fonctionnalités de Riot:

<todo>

  <h3>{ opts.title }</h3>

  <ul>
    <li each={ items }>
      <label class={ completed: done }>
        <input type="checkbox" checked={ done } onclick={ parent.toggle }> { title }
      </label>
    </li>
  </ul>

  <form onsubmit={ add }>
    <input name="input" onkeyup={ edit }>
    <button disabled={ !text }>Add #{ items.length + 1 }</button>
  </form>

  <script>
    this.items = opts.items

    edit(e) {
      this.text = e.target.value
    }

    add(e) {
      if (this.text) {
        this.items.push({ title: this.text })
        this.text = this.input.value = ''
      }
    }

    toggle(e) {
      var item = e.item
      item.done = !item.done
      return true
    }
  </script>

</todo>

Les tags personnalisés sont compilés en JavaScript.

Regardez la démo en ligne, consultez les sources, ou téléchargez le zip.

Syntaxe de tag

Un tag Riot est une combinaison d’éléments HTML et de logique JavaScript. Voilà les règles de base:

La définition de tag dans les fichiers tag commence toujours en début de ligne:

<!-- fonctionne -->
<my-tag>

</my-tag>

<!-- fonctionne aussi -->
<my-tag></my-tag>

  <!-- ne fonctionne pas, à cause de l'indentation -->
  <my-tag>

  </my-tag>

Les définitions de tag inline (directement dans le corps du document) doivent être indentées proprement, avec tous les tags personnalisés indentés au plus petit niveau d’indentation. Mélanger tabulations et espaces est déconseillé.

Pas de balise script

Vous pouvez omettre la balise <script> dans une définition de tag:

<todo>

  <!-- balisage -->
  <h3>{ opts.title }</h3>

  // logique
  this.items = [1, 2, 3]

</todo>

Dans ce cas, la logique commence après la fermeture de la dernière balise HTML. Cette syntaxe “ouverte” est couramment utilisée dans les exemples de ce site.

Préprocesseur

Vous pouvez spécifier un préprocesseur avec l’attribut type. Par exemple:

<my-tag>
  <script type="coffee">
    # la logique coffeescript vient ici
  </script>
</my-tag>

Les options actuellement disponibles sont “coffee”, “typescript”, “es6” et “none”. Vous pouvez également préfixer le langage avec “text/”, par exemple “text/coffee”.

Voir la section Préprocesseurs pour plus de détails.

Style du tag

Vous pouvez utiliser une balise style à l’intérieur d’une définition de tag. Riot la récupère automatiquement pour l’injecter dans <head>. Cela ne survient qu’une seule fois, peu importe le nombre de fois où le tag est initialisé.

<todo>

  <!-- balisage -->
  <h3>{ opts.title }</h3>

  <style>
    todo { display: block }
    todo h3 { font-size: 120% }
    /** autres stymes spécifiques au tag **/
  </style>

</todo>

CSS à portée définie (:scope)

Les styles CSS à portée définie sont également disponibles. Cet exemple équivaut au premier:

<todo>

  <!-- layout -->
  <h3>{ opts.title }</h3>

  <style scoped>
    :scope { display: block }
    h3 { font-size: 120% }
    /** autres styles spécifiques au tag **/
  </style>

</todo>

Pour rendre plus facile la surcharge du CSS, vous pouvez indiquer à quel endroit dans le <head> Riot doit injecter les styles avec cette balise:

<style type="riot"></style>

Un cas d’usage serait par exemple d’insérer les styles de tag d’une bibliothèque de composants après normalize.css mais avant le thème de votre site web, ce qui vous permet de surcharger le style par défaut des tags.

Montage

Une fois votre tag créé, vous devez le monter sur la page comme ceci:

<body>

  <!-- placer le tag personnalisé n'importe où dans le body -->
  <todo></todo>

  <!-- inclure riot.js -->
  <script src="riot.min.js"></script>

  <!-- inclure le tag -->
  <script src="todo.js" type="riot/tag"></script>

  <!-- monter le tag -->
  <script>riot.mount('todo')</script>

</body>

Les tags personnalisés définis à l’intérieur du body de la page doivent être fermés normalement: <todo></todo> ; l’auto-fermeture <todo/> n’est pas supportée dans ce cas.

Voici quelques exemples d’utilisation de la méthode mount:

// monte tous les tags personnalisés de la page
riot.mount('*')

// monte un élément avec un id spécifique
riot.mount('#my-element')

// monte les éléments sélectionnés
riot.mount('todo, forum, comments')

Un document peut contenir plusieurs instances du même tag.

Accéder aux éléments du DOM

Riot vous donne accès aux éléments qui ont un attribut name directement via le mot-clé this dans le tag, ainsi que de nombreux raccourcis tels que l’attribut if="{...}". Mais occasionnellement, vous avez besoin de récupérer et de toucher à des bouts de HTML qui ne rentrent pas dans les cas d’usage de ces fonctions préconçues.

Comment utiliser jQuery, Zepto, querySelector, etc…

Si vous avez besoin d’accéder au DOM à l’intérieur de Riot, jetez un oeil au Cycle de Vie du Tag et notez que les éléments du DOM ne sont pas instanciés avant que l’événement update() ne survienne la première fois, ce qui signifie que toute tentative pour sélectionner un élément du DOM avant cet événement échouera.

<example-tag>
  <p id="findMe">Est-ce que j'existe ?</p>

  <script>
  var test1 = document.getElementById('findMe')
  console.log('test1', test1)  // Echec

  this.on('update', function(){
    var test2 = document.getElementById('findMe')
    console.log('test2', test2) // Succès
  })
  </script>
</example-tag>

Vous ne voulez sans doute pas répéter cette sélection des éléments à chaque événement update. Au lieu de ça, vous pouvez écouter l’événement mount.

<example-tag>
  <p id="findMe">Est-ce que j'existe ?</p>

  <script>
  var test1 = document.getElementById('findMe')
  console.log('test1', test1)  // Echec

  this.on('update', function(){
    var test2 = document.getElementById('findMe')
    console.log('test2', test2) // Succès, déclenché à chaque update
  })

  this.on('mount', function(){
    var test3 = document.getElementById('findMe')
    console.log('test3', test3) // Succès, déclenché qu'une seule fois par montage
  })
  </script>
</example-tag>

Requête DOM contextualisée

Maintenant que nous savons comment récupérer des références aux éléments du DOM en attendant les événements update ou mount, nous pouvons également ajouter un contexte à nos requêtes DOM sur l’`élément racine (l’élement correspondant au tag que nous sommes en train de créer). De cette manière, nous avons l’assurance de sélectioner uniquement les éléments à l’intérieur du tag.

<example-tag>
  <p id="findMe">Est-ce que j'existe ?</p>
  <p>Est-ce cela la vraie vie ?</p>
  <p>Ou est-ce seulement un rêve ?</p>

  <script>
  this.on('mount', function(){
    // Appel jQuery contextualisé
    $('p', this.root)

    // Appel à querySelector contextualisé
    this.root.querySelectorAll('p')
  })
  </script>
</example-tag>

Options

Vous pouvez passer des options aux tags dans le second argument

<script>
riot.mount('todo', { title: 'Ma Todo-List', items: [ ... ] })
</script>

Les données passées peuvent être n’importe quoi, d’un simple objet à l’API entière d’une application. Ou bien un store Flux. Tout dépend de l’architecture choisie.

A l’intérieur du tag, les options sont référencées avec la variable opts comme ceci:

<my-tag>

  <!-- Options dans le HTML -->
  <h3>{ opts.title }</h3>

  // Options dans le JavaScript
  var title = opts.title

</my-tag>

Cycle de vie du tag

Un tag est créé en suivant la séquence suivante:

  1. Le tag est construit
  2. La logique JavaScript du tag est exécutée
  3. Les expressions HTML sont calculées et l’événement “update” est déclenché
  4. Le tag est monté sur la page et l’événement “mount” est déclenché

Une fois le tag monté, les expressions sont mises à jour comme ceci:

  1. Automatiquement après qu’un callback d’événement soit appelé. (à moins que vous ayez appliqué event.preventUpdate = true dans le callback de cet événement).
  2. Lorsque this.update() est appelé sur l’instance courante du tag
  3. Lorsque this.update() est appelé sur le tag parent, ou un parent du parent. Les mises à jour se propagent unilatéralement du parent au tag enfant.
  4. Lorsque riot.update() est appelé, ce qui met à jour toutes les expressions sur la page.

L’événement update est déclenché à chaque fois que le tag est mis à jour.

Puisque les valeurs sont calculées avant montage, il n’y a pas de problèmes inattendus au montage tels que des appels en échec avec <img src={ src }>.

Ecouter les évènements du cycle de vie

Vous pouvez réagir à divers évènements du cycle de vie à l’intérieur du tag comme ceci:

<todo>

  this.on('before-mount', function() {
    // avant que le tag soit monté
  })

  this.on('mount', function() {
    // juste après que le tag soit monté sur la page
  })

  this.on('update', function() {
    // permet de recalculer les données de contexte avant la mise à jour
  })

  this.on('updated', function() {
    // juste après que le tag soit mis à jour
  })

  this.on('before-unmount', function() {
    // avant que le tag soit supprimé
  })

  this.on('unmount', function() {
    // lorsque le tag est supprimé de la page
  })

  // curieux de connaître tous les évènements ?
  this.on('*', function(eventName) {
    console.info(eventName)
  })

</todo>

Vous pouvez avoir plusieurs gestionnaires d’évènements pour le même évènement. Consultez la section Observable pour plus de détails sur les évènements.

Mixins

Les Mixins sont un moyen simple de partager des fonctionnalités entre tags. Une fois le tag compilé par Riot, tous les mixins définis sont ajoutés et disponibles à l’utilisation dans le tag.

var OptsMixin = {
  init: function() {
    this.on('updated', function() { console.log('Updated!') })
  },

  getOpts: function() {
    return this.opts
  },

  setOpts: function(opts, update) {
    this.opts = opts
    if (!update) this.update()
    return this
  }
}

<my-tag>
  <h1>{ opts.title }</h1>

  this.mixin(OptsMixin)
</my-tag>

Dans cet exemple, vous donnez à chaque instance de my-tag les fonctionnalités de OptsMixin qui fournit les méthodes getOpts et setOpts. La méthode init est une méthode spéciale servant à initialiser le mixin une fois chargé dans le tag. (cette méthode init n’est pas accessible en dehors du tag dans laquelle elle est définie)

var my_tag_instance = riot.mount('my-tag')[0]

console.log(my_tag_instance.getOpts()) // affichera toutes les options du tag

Les tags acceptent en mixin n’importe quel objet de la forme – {'key': 'val'} var mix = new function(...) – et renverront une erreur si un autre type de données est passé en mixin.

La définition de my-tag comporte maintenant une méthode getId ajoutée aux côtés de celles définies par le mixin OptsMixin, à l’exception de la fonction init.

function IdMixin() {
  this.getId = function() {
    return this._id
  }
}

var id_mixin_instance = new IdMixin()

<my-tag>
  <h1>{ opts.title }</h1>

  this.mixin(OptsMixin, id_mixin_instance)
</my-tag>

En étant définis au niveau du tag, les mixins n’étendent pas seulement les fonctionnalités de votre tag, mais permettent également d’obtenir une interface réutilisable. Chaque fois qu’un tag est monté, même un sous-tag, l’instance disposera du code du mixin.

Mixins partagés

Pour partager les mixins entre des fichiers ou des projets, l’API riot.mixin est fournie. Vous pouvez inscrire votre mixin partagé comme ceci:

riot.mixin('nomDuMixin', objetMixin)

Pour ensuite charger ce mixin dans le tag, utilisez la méthode mixin() avec le nom donné au mixin.

<my-tag>
  <h1>{ opts.title }</h1>

  this.mixin('nomDuMixin')
</my-tag>

Mixins globaux

Si vous avez besoin d’ajouter une fonctionnalité à tous vos tags, vous pouvez enregistrer un mixin global comme ceci:

// Doit être inscrit avant de monter les tags
riot.mixin(mixinObject)

Contrairement aux mixins partagés, les globaux sont automatiquement chargés pour tous les tags montés. Utilisez donc avec prudence !

riot.mixin('globalMixinOne', mixinObjectOne, true)
console.log(riot.mixin('globalMixinOne') === mixinObjectOne) // true

Parfois vous pouvez avoir besoin de récupérer l’objet mixin afin de l’assigner globalement juste par son nom. Dans ce cas, le troisième paramètre booléen indique que la mixin n’est pas partagée mais est une mixin globale.

Expressions

Le HTML peut être mélangé avec des expressions à l’intérieur d’accolades:

{ /* mon expression va ici */ }

Les expressions peuvent assigner des attributs ou modifier les noeuds textes imbriqués:

<h3 id={ /* attribute_expression */ }>
  { /* nested_expression */ }
</h3>

Les expressions sont du JavaScript à 100%. Quelques exemples:

{ title || 'Untitled' }
{ results ? 'ready' : 'loading' }
{ new Date() }
{ message.length > 140 && 'Message is too long' }
{ Math.round(rating) }

Le but est de garder vos expressions courtes et simples afin que le HTML reste aussi propre que possible. Si votre expression devient trop complexe, vous devriez considérer le fait de déplacer la logique dans l’événement update. Par exemple:

<my-tag>

  <!-- la valeur `val` est calculée plus bas .. -->
  <p>{ val }</p>

  // ..à chaque mise à jour
  this.on('update', function() {
    this.val = some / complex * expression ^ here
  })
</my-tag>

Attributs booléens

Les attributs booléens (checked, selected etc..) sont ignorés quand l’expression équivaut à false:

<input checked={ null }> devient <input>.

Le W3C établit qu’une propriété booléenne est vraie si l’attribut est présent — même s’il n’y a pas de valeur ou si elle est égale à false.

L’expression suivante ne fonctionne pas:

<input type="checkbox" { true ? 'checked' : ''}>

puisque seuls les expressions à l’intérieur d’attributs ou de noeuds textes sont valides. Riot détecte 44 attributs booléens différents.

Notation raccourcie pour les classes

Riot a une syntaxe spéciale pour les noms de classes CSS. Par exemple:

<p class={ foo: true, bar: 0, baz: new Date(), zorro: 'a value' }></p>

sera évalué comme “foo baz zorro”. Les noms de propriétés dont la valeur équivaut à true seront ajoutés à la liste des noms de classes. Bien sûr, vous pouvez utiliser cette notation à d’autres endroits que les noms de classe si vous trouvez un cas d’utilisation adéquat.

Afficher des accolades

Vous pouvez afficher une expression sans qu’elle soit évaluée en échappant l’accolade ouvrante:

\\{ ceci n'est pas évalué \\} affichera { ceci n'est pas évalué }

Personnaliser les accolades

Vous êtes libre de personnaliser la notation des expressions comme bon vous semble. Par exemple:

riot.settings.brackets = '${ }'
riot.settings.brackets = '\{\{ }}'

Les notations de début et de fin d’expression sont séparées par un caractère espace.

Si vous utilisez le précompilateur, vous devrez également configurer l’option brackets.

Note

Les expressions à l’intérieur des balises style sont ignorées.

Afficher du HTML non échappé

Les expressions Riot peuvent uniquement afficher du texte sans formattage HTML. Cependant, vous pouvez déclarer votre propre tag personnalisé à cet effet. Par exemple:

<raw>
  <span></span>

  this.root.innerHTML = opts.content
</raw>

Une fois le tag défini, vous pouvez l’utiliser à l’intérieur d’autres tags. Par exemple:

<my-tag>
  <p>Voici du contenu HTML à l'état brut: <raw content="{ html }"/> </p>

  this.html = 'Hello, <strong>world!</strong>'
</my-tag>

Démo sur jsfiddle

attention Ne pas échapper le HTML sortant peut exposer l’utilisateur à des attaques de type XSS donc assurez-vous de ne jamais utiliser de données ne provenant pas d’une source de confiance.

Tags imbriqués

Définissons un tag parent <account> contenant un tag imbriqué <subscription>:

<account>
  <subscription plan={ opts.plan } show_details="true" />
</account>


<subscription>
  <h3>{ opts.plan.name }</h3>

  // Gérer les options en JS
  var plan = opts.plan,
      show_details = opts.show_details

  // accéder au tag parent
  var parent = this.parent

</subscription>

important Notez comment nous avons nommé l’attribut show_details en utilisant un underscore au lieu de la notation camelCase, qui aurait été convertie automatiquement en minuscules à cause de la spécification navigateur.

Ensuite nous montons le tag account sur la page avec une option de configuration plan:

<body>
  <account></account>
</body>

<script>
riot.mount('account', { plan: { name: 'small', term: 'monthly' } })
</script>

Les options du tag parent sont passées avec la méthode riot.mount et les options du tag enfant sont passées par l’attribut du tag.

important les tags imbriqués sont toujours déclarés à l’intérieur d’un tag parent. Ils ne sont pas initialisés s’ils sont définis sur la page.

HTML imbriqué

La “transclusion HTML” est un moyen de traiter le HTML interne d’une page. Ceci est accompli grâce au tag <yield> inclus dans Riot. Exemple:

Définition du tag

<my-tag>
  <p>Hello <yield/></p>
  this.text = 'world'
</my-tag>

Utilisation

Le tag personnalisé dans la page avec du HTML imbriqué à l’intérieur

<my-tag>
  <b>{ text }</b>
</my-tag>

Résultat

<my-tag>
  <p>Hello <b>world</b><p>
</my-tag>

Voir la documentation API pour en savoir plus sur yield.

Elements nommés

Les éléments avec des attributs name ou id sont automatiquement attachés au contexte afin que vous puissiez y accéder facilement en JavaScript:

<login>
  <form id="login" onsubmit={ submit }>
    <input name="username">
    <input name="password">
    <button name="submit">
  </form>

  // récupérer les éléments HTML ci-dessus
  var form = this.login,
    username = this.username.value,
    password = this.password.value,
    button = this.submit

</login>

Bien sûr, ces éléments nommés peuvent également être utilisés dans les expression dans le HTML: <div>{ username.value }</div>

Gestionnaires d’événements

Une fonction traitant avec des événements du DOM est appelée “gestionnaire d’événement”. Les gestionnaires d’événements sont définis comme ceci:

<login>
  <form onsubmit={ submit }>

  </form>

  // cette méthode est appelée quand le formulaire ci-dessus est soumis
  submit(e) {

  }
</login>

Les attributs commençant par “on” (onclick, onsubmit, oninput etc…) acceptent comme valeur une fonction qui sera appelée quand l’événement correspondant surviendra. Cette fonction peut également être définie dynamiquement suivant une expression. Par exemple:

<form onsubmit={ condition ? methode_a : methode_b }>

Dans la fonction, this se réfère à l’instance courante de tag. Chaque fois que le gestionnaire est appelé, this.update() est automatiquement appelé ensuite pour réagir à tous les éventuels changements dans l’interface utilisateur.

Le comportement par défaut des gestionnaires d’événeents est d’automatiquement annuler l’événement à moins que l’élément soit une case à cocher ou un bouton radio. Cela signifie que e.preventDefault() est déjà appelé pour vous, parce qu’il s’agit généralement du comportement désiré (ou celui que vous avez oublié de définir). Vous pouvez laisser le navigateur effectuer l’action par défaut en retournant simplement true dans le gestionnaire.

Par exemple, ce gestionnaire de soumission déclenchera effectivement la soumission du formulaire au serveur:

submit() {
  return true
}

Objet événement

Le gestionnaire d’événement reçoit l’objet standard événement en tant que premier argument. Les propriétés suivantes sont normalisées pour fonctionner à travers tous les navigateurs:

Conditions

Les conditions vous permettent d’afficher/cacher des éléments selon une condition. Par exemple:

<div if={ is_premium }>
  <p>Ce contenu est réservé aux utilisateurs premium</p>
</div>

Une fois encore, cette expression peut être une simple propriété ou une expression JavaScript complète. Les attributs spéciaux suivants sont disponibles:

L’opérateur d’égalité est == et non ===. Par exemple: 'a string' == true.

important Utiliser des attributs conditionnels sur des tags imbriqués n’empêche pas Riot d’évaluer les expressions cachées à l’intérieur - nous travaillons sur un patch pour résoudre ce problème

Boucles

Les boucles sont implémentées avec l’attribut each comme ceci:

<todo>
  <ul>
    <li each={ items } class={ completed: done }>
      <input type="checkbox" checked={ done }> { title }
    </li>
  </ul>

  this.items = [
    { title: 'Premier item', done: true },
    { title: 'Second item' },
    { title: 'Troisième item' }
  ]
</todo>

L’élément avec l’attribut each sera répété pour chacun des éléments de la liste. Les nouveaux éléments sont automatiquement ajoutés/créés lorsque la liste des éléments est manipulée en utilisant les méthodes push(), slice() ou splice par exemple.

Contexte

Un nouveau contexte est créé pour chaque élément de la boucle. Ce sont des instances de tag. Quand des boucles sont imbriquées, les tags enfants dans la boucle héritent de toutes les propriétés et méthodes de la boucle parenet, si elles ne sont pas déjà définies. En ce sens, Riot évite de surcharger ce qui ne doit pas l’être par le tag parent.

On peut accéder au parent explicitement via la variableparent. Par exemple:

<todo>
  <div each={ items }>
    <h3>{ title }</h3>
    <a onclick={ parent.remove }>Supprimer</a>
  </div>

  this.items = [ { title: 'Premier' }, { title: 'Second' } ]

  remove(event) {

  }
</todo>

Dans l’élément bouclé, tout appartient au contexte enfant sauf l’attribut each, donc on peut accéder directement à title et remove doit être préfixé avec parent. puisque la méthode n’est pas une propriété de l’élément bouclé.

Les éléments bouclés sont des instances de tag. Riot ne touche pas aux éléments originaux donc aucune nouvelle propriété ne leur est ajoutée.

Gestionnaire d’événements sur les éléments d’une boucle

Les gestionnaires d’événements peuvent accéder aux éléments individuels d’une collection avec event.item. Maintenant, implémentons la fonction remove:

<todo>
  <div each={ items }>
    <h3>{ title }</h3>
    <a onclick={ parent.remove }>Supprimer</a>
  </div>

  this.items = [ { title: 'Premier' }, { title: 'Second' } ]

  remove(event) {

    // élément bouclé
    var item = event.item

    // index dans la collection
    var index = this.items.indexOf(item)

    // supprimer de la collection
    this.items.splice(index, 1)
  }
</todo>

Une fois le gestionnaire d’événement exécuté, l’instance courante du tag est actualisée avec this.update() (à moins que vous ayez assigné e.preventUpdate à true dans votre gestionnaire d’événement), ce qui actualise également tous les éléments bouclés. Le parent remarque qu’un élément a été retiré de la collection et supprime le noeud du DOM correspondant.

Boucler sur des tags personnalisés

Vous pouvez également boucler sur des tags personnalisés. Par exemple:

<todo-item each="{ items }" data="{ this }"></todo-item>

L’élément en cours dans l’itération est référencé par this , que vous pouvez passer en option au tag personnalisé répété.

Elements de listes non-objets

Les éléments de la liste sur laquelle boucler ne doivent pas nécessairement être des objets. Il peut aussi bien s’agir de nombres ou de chaînes de caractères. Dans ce cas, vous devez utiliser la notation { value, i in items } comme ceci:

<my-tag>
  <p each="{ value, i in arr }">{ i }: { value }</p>

  this.arr = [ true, 110, Math.random(), 'quatre']
</my-tag>

La variable value est la valeur de l’élément et i est le nombre index dans la liste. Ces deux variables peuvent être renommées pour décrire au mieux la situation.

Boucles d’objets

Il est également possible de boucler sur les propriétés d’objets classiques. Par exemple:

<my-tag>
  <p each="{ key, value in obj }">{ key } = { value }</p>

  this.obj = {
    key1: 'value1',
    key2: 1110.8900,
    key3: Math.random()
  }
</my-tag>

Boucler sur des objets n’est pas recommandé car Riot utilis en interne JSON.stringify pour comparer les objets. L’objet entier est étudié et dès qu’un changement est repéré, toute la boucle est réinterprétée. Cela peut être lent. Les listes classiques sont bien plus rapides et seuls les éléments changeants sont redessinés sur la page.

Conseils avancés sur les boucles

Performances

Dans riot v2.3, pour rendre les boucles plus fiables, les éléments du DOM seront déplacés, insérés ou supprimés toujours en synchronisation avec vos collections de données: cette stratégie ralentit un peu le rendu des boucles comparé à la version précédente 2.2. Pour utiliser l’ancien algorithme plus rapide , vous pouvez ajouter l’attribut no-reorder aux noeuds bouclés. Par exemple:

<loop>
  <div each="{ item in items }" no-reorder>{ item }</div>
</loop>

Tag virtuel virtual

expérimental

Dans certains cas, vous pouvez avoir besoin de répéter un code HTML sans avoir de nouvel élément qui emballe le tout. Vous pouvez alors utiliser le tag <virtual> qui sera supprimé au montage, ne laissant que les éléments contenus à l’intérieur. Par exemple:

<dl>
  <virtual each={item in items}>
    <dt>{item.key}</dt>
    <dd>{item.value}</dd>
  </virtual>
</dl>

Elements HTML en guise de tags Riot

Les éléments standard HTML peuvent être utilisés comme des tags Riot dans le corps de la page en ajoutant l’attribut riot-tag. Depuis riot 2.3.17, nous avons aussi introduit l’attribut data-is pour associer des tags Riot à des éléments du DOM.

<ul riot-tag="my-tag"></ul>

important L’utilisation de l’attribut riot-tag est dépréciée en faveur de data-is, en prévision de la prochaine release majeure de riot.

Cela fournit aux utilisateurs une alternative pour une plus grande compatibilité avec les frameworks CSS. Ces tags sont traités comme les autres.

riot.mount('my-tag')

On monte l’élément ul ci-dessus comme s’il s’agissait de <my-tag></my-tag>

Rendu côté serveur

Riot supporte le rendu côté serveur avec Node/io.js. Vous pouvez utiliser require pour charger les tags et leur passer des données:

var riot = require('riot')
var timer = require('timer.tag')

var html = riot.render(timer, { start: 42 })

console.log(html) // <timer><p>Secondes écoulées: 42</p></timer>

Les boucles et conditions sont supportées.