Dans ce tutoriel je vous propose de découvrir comment créer une infobulle en utilisant du JavaScript (avec la syntaxe ES2015).
Pourquoi pas en CSS
Il est possible de créer une petite bulle d'information en utilisant simplement du CSS. Cela fonctionne dans des cas simples mais il est difficile d'étendre le système (pour accueillir de l'HTML par exemple).
L'algorithme
Avant de nous lancer dans le code il est important de réfléchir au déroulement de notre algorithme :
/*
On sélectionne les éléments avec un attribut particulier (a[title])
Lorsque l'on survole un élément {
On crée une <diV> dans le <body>
On remplit la <div> avec le texte correspondant au titre
On positionne la bulle au dessus de l'élément
On ajoute une classe, pour animer l'apparition
}
Lorsque l'on quitte le survole {
On retire une classe, pour animer la disparition
Lorsque l'animation se termine {
On supprime la <div> du <body>
}
}
*/
Pour avoir un code simple et adaptable, nous allons utiliser une classe qui fonctionnera de la manière suivante :
Tooltip.bind('a[title]')
Pour le moment le système va fonctionner avec l'attribut title
d'un lien ou un attribut data-tooltip
mais il est possible d'ajouter des comportements supplémentaires en modifiant le comportement du constructeur.
class Tooltip {
/**
* Applique le système de bulle d'infos sur les éléments
* @param {string} selector
*/
static bind (selector) {
document.querySelectorAll(selector).forEach(element => new Tooltip(element))
}
/**
* @param {HTMLElement} element
*/
constructor (element) {
this.element = element
let tooltipTarget = this.element.getAttribute('data-tooltip')
if (tooltipTarget) {
this.title = document.querySelector(tooltipTarget).innerHTML
} else {
this.title = element.getAttribute('title')
}
this.tooltip = null
this.element.addEventListener('mouseover', this.mouseOver.bind(this))
this.element.addEventListener('mouseout', this.mouseOut.bind(this))
}
mouseOver () {
let tooltip = this.createTooltip()
let width = tooltip.offsetWidth
let height = tooltip.offsetHeight
let left = this.element.offsetWidth / 2 - width / 2 + this.element.getBoundingClientRect().left + document.documentElement.scrollLeft
let top = this.element.getBoundingClientRect().top - height - 15 + document.documentElement.scrollTop
if (left < 20) {
left = 20
}
tooltip.style.left = left + "px"
tooltip.style.top = top + "px"
tooltip.classList.add('visible')
}
mouseOut () {
if (this.tooltip !== null) {
this.tooltip.classList.remove('visible')
this.tooltip.addEventListener('transitionend', () => {
if (this.tooltip !== null) {
document.body.removeChild(this.tooltip)
this.tooltip = null
}
})
}
}
/**
* Crée et injecte la bulle d'info dans l'HTML
* @returns {HTMLElement}
*/
createTooltip () {
if (this.tooltip === null) {
let tooltip = document.createElement('div')
tooltip.innerHTML = this.title
tooltip.classList.add('tippy')
document.body.appendChild(tooltip)
this.tooltip = tooltip
}
return this.tooltip
}
}