1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| <!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Changement de fond au survol</title>
<style>
body {
background-image: url('img/FOND3.jpg');
background-size: cover;
background-color: black;
color: white;
}
body.fond-alternatif {
background-color: red;
}
.cadre {
width: 300px;
height: 300px;
background: rgba(196, 255, 112, 0.5);
}
.cadre div {
width: 60px;
height: 60px;
display: inline-block;
margin: 1em;
background: rgba(255, 255, 255, 0.5);
}
</style>
</head>
<body>
<h1>Changement de fond au survol</h1>
<div class="cadre">
<div></div> <div></div> <div></div>
</div>
<script> "use strict";
// changement : over reçoit une URL en paramètre, et on nagit plus sur la classe,
// on manipule directement backgroundImage
const over = (imageUrl) => {
document.body.style.backgroundImage = `url('${imageUrl}')`;
};
const out = () => {
document.body.style.backgroundImage = "";
};
const isDescendant = (aChild, aParent) => {
if (!aChild || !aParent) return false;
let found = false;
let element = aChild.parentElement;
while (!found && element) {
if (element === aParent) found = true;
element = element.parentElement;
}
return found;
};
// on nécoute pas tout de suite lévènement mouseover,
// on attend davoir décodé les images
document.addEventListener("mouseout", (event) => {
if (event.target.matches(".cadre")) {
if (!isDescendant(event.relatedTarget, event.target)) {
console.log("%cmouseout%c on en veut bien", "color: cyan", "");
out();
}
else {
console.log("%cmouseout%c non merci", "color: cyan", "");
}
}
});
// les images décodées sont représentées sous forme de blobs,
// il faut les révoquer au déchargement de la page pour libérer la mémoire
const urlsToRevoke = [];
window.addEventListener("unload", () => {
console.log(`revoking object URLs now (length = ${urlsToRevoke.length})`);
for (const url of urlsToRevoke) {
URL.revokeObjectURL(url);
}
});
// la fonction de décodage, elle renvoie une promesse
const decodeImage = (imageUrl) => new Promise((resolve, reject) => {
const $img = document.createElement("img");
$img.addEventListener("error", (error) => {
// en cas derreur de chargement de limage, on rejette la promesse
reject(error);
});
$img.addEventListener("load", (loadEvent) => {
if ($img.complete && $img.naturalWidth > 0) {
// crée un canevas aux dimensions de limage
const $canvas = document.createElement("canvas");
$canvas.width = $img.naturalWidth;
$canvas.height = $img.naturalHeight;
// dessine limage dans le canevas
const cx = $canvas.getContext("2d");
cx.drawImage($img, 0, 0);
// crée un blob à partir du canevas
$canvas.toBlob((blob) => {
// crée une URL « blob: »
const blobURL = URL.createObjectURL(blob);
urlsToRevoke.push(blobURL);
// on résoud la promesse avec lURL du blob
resolve(blobURL);
}, { type: "image/bmp" }); // type bitmap = sans compression
}
});
// initie le chargement de limage
$img.src = imageUrl;
});
decodeImage("img/FOND3spitz.jpg").then((blobURL) => {
// la fonction .then() est appelée quand la promesse est résolue,
// on peut alors écouter mouseover
document.addEventListener("mouseover", (event) => {
if (event.target.matches(".cadre")) {
if (!isDescendant(event.relatedTarget, event.target)) {
console.log("%cmouseover%c on en veut bien", "color: orange", "");
over(blobURL);
}
else {
console.log("%cmouseover%c non merci", "color: orange", "");
}
}
});
});
</script>
</body>
</html> |