Il s'agit d'un vieux sujet et @jfriend00 a fait un très bon travail en expliquant les bases derrière les appels de fonctions de fermeture.
Mettons à jour les snippets en ES6 et utilisons également une autre technique qui pourrait nous aider à surmonter ce genre de scénarios.
Définissons d'abord une fonction handler
cette fonction recevra deux paramètres fnc
y val
où les fnc
est la fonction personnalisée qui gérera l'événement ; elle est généralement nommée on
+ theEventName
dans ce cas onClickEvent
. Il n'y a rien de nouveau ici. Définissons maintenant le onclick
sur l'élément red
et il s'appellera clickEventHandler
comme ceci :
red.onclick = clickEventHandler
Comme nous l'avons remarqué clickEventHandler
n'a pas de paramètre Teo, comment puis-je envoyer le event
et le index
au gestionnaire ?
Bonne question, appelons d'abord le handler
pour créer notre fonction onClickEvent
manipulateur comme ceci :
handler(onClickEvent, index)
Mais Teo, onClickEvent
n'a pas non plus de paramètres, Comment envoyer la fonction de fermeture onClickEvent
, le event
produit par onclick
y index
valeur ?
Patience, mon jeune padawan. Tout d'abord, quelle fonction gérera le event
? Dans notre scénario, il y aura onClickEvent
Définissons donc cette fonction pour recevoir le event
e
et le index
valeur v
:
function onClickEvent(e, v) {
console.log(`${e.currentTarget.className} -> [x: ${e.x}, y: ${e.y}] | val: ${v}`)
}
Nous allons maintenant mettre en œuvre notre fonction de traitement. Cette fonction renverra une définition de fonction de fermeture qui exécutera la fonction définie dans la section fnc
La fonction de fermeture et la fonction de fermeture sont également fusionnées pour obtenir les paramètres reçus par la fonction de fermeture et la fonction de fermeture. val
paramenter comme ceci :
function handler(fnc, val) {
return (...params) => {
const ctx = this
const arg = [...params, val]
fnc.apply(ctx, arg)
}
}
Pour appeler le fnc
nous avons utilisé apply()
. Cette méthode appelle la fonction spécifiée avec un contexte a donné ctx
et arg
en tant qu'arguments fournis sous la forme d'un tableau. Par conséquent, la fonction fnc
est exécuté dans le contexte de la fonction de fermeture ctx
.
Il s'agit d'un extrait fonctionnel pour ce scénario.
const red = document.querySelector('.red')
const blue = document.querySelector('.blue')
function handler(fnc, val) {
return (...params) => {
const ctx = this
const arg = [...params, val]
fnc.apply(ctx, arg)
}
}
function onClickEvent(e, v) {
console.log(`${e.currentTarget.className} -> [x: ${e.x}, y: ${e.y}] | val: ${v}`)
}
const index = 50
// Define the handler function
const clickEventHandler = handler(onClickEvent, index)
// Call the debounced function on every mouse move
red.onclick = clickEventHandler
blue.addEventListener('click', clickEventHandler)
.boxes {
width: 100%;
height: 120px;
display: flex;
flex-flow: row nowrap;
}
.red {
background: red;
}
.blue {
background: blue;
}
.box {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
<div class='boxes'>
<div class='red box'>Click Me</div>
<div class='blue box'>Not ready</div>
</div>
Maintenant, nous allons appliquer ce concept à votre scénario :
const red = document.querySelector('.red')
const blue = document.querySelector('.blue')
red.clicked = false
let clickEventHandler
function handler(fnc, val) {
return (...params) => {
const ctx = this
const arg = [...params, val]
fnc.apply(ctx, arg)
}
}
function onRedClickEvent(e) {
if (red.clicked) return
red.clicked = true
red.textContent = 'Clicked'
blue.textContent = 'Ready'
console.log(`${e.currentTarget.className} -> blue is ready`)
// Define the handler function
clickEventHandler = handler(onClickEvent, red)
// Call the debounced function on every mouse move
blue.addEventListener('click', clickEventHandler)
}
function onClickEvent(e, elem) {
red.clicked = false
red.textContent = 'Click Me'
blue.textContent = 'Not Ready'
console.log(`${e.currentTarget.className} -> [x: ${e.x}, y: ${e.y}] | elem: ${elem.className}`)
blue.removeEventListener('click', clickEventHandler)
}
red.onclick = onRedClickEvent
.boxes {
width: 100%;
height: 120px;
display: flex;
flex-flow: row nowrap;
}
.red {
background: red;
}
.blue {
background: blue;
}
.box {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
color: white;
user-select: none;
}
<div class='boxes'>
<div class='red box'>Click Me</div>
<div class='blue box'>Not ready</div>
</div>