You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
8.1 KiB

---
gitea: none
include_toc: true
---
[TOC]
# Sélectionner des éléments HTML
- Sélectionner un élément à partir d'un sélecteur CSS :
```javascript
document.querySelector($CSS_SELECTOR) // retourne un noeud ou undefined.
```
- Sélectionner tous les éléments à partir d'un sélecteur CSS :
```javascript
document.querySelectorAll($CSS_SELECTOR) // retourne une liste
```
- Sélectionner un élément descendant de `$ELEM` à partir d'un sélecteur CSS :
```javascript
$ELEM.querySelector($CSS_SELECTOR) // retourne un noeud ou undefined.
```
- Sélectionner un élément ancestre de `$ELEM` à partir d'un sélecteur CSS :
```javascript
$ELEM.closest($CSS_SELECTOR) // retourne un noeud ou undefined.
```
- Est-ce que `$ELEM` correspond au sélecteur CSS ?
```javascript
$ELEM.matches($CSS_SELECTOR) // retourne un booléen.
```
💡 En Typescript, vous pouvez préciser le type de retour :
```typescript
document.querySelector<HTMLDivElement>($CSS_SELECTOR) // retourne un DIV
```
# Modifier un élément HTML
- Classes :
```javascript
$ELEM.classList.add($CLASSNAME)
$ELEM.classList.remove($CLASSNAME)
$ELEM.classList.toggle($CLASSNAME [, $FORCE]) // "alterner"
$ELEM.classList.contains($CLASSNAME) // retourne un booléen
```
- Attributs :
```javascript
$ELEM.getAttribute($ATTR_NAME)
$ELEM.setAttribute($ATTR_NAME, $ATTR_VALUE)
$ELEM.removeAttribute($ATTR_NAME)
$ELEM.toggleAttribute($ATTR_NAME [, $FORCE]) // "alterner"
$ELEM.hasAttribute($ATTR_NAME) // retourne un booléen
```
- Interface dataset:
```javascript
// data-toto-foo ($ATTR_NAME) => totoFoo ($DATA_NAME)
$ELEM.dataset[$DATA_NAME] // retourne la valeur
$ELEM.dataset[$DATA_NAME] = $DATA_VALUE
delete $ELEM.dataset[$DATA_NAME] // [JS] Javascript
del $ELEM.dataset[$DATA_NAME] // [🐍] Python
($DATA_NAME in $ELEM.dataset) // retourne un booléen
```
💡 Vous pouvez parcourir `$ELEM.classList`, `$ELEM.dataset`, et `$ELEM.getAttributeNames()` :
```javascript
// [JS] Javascript
for( let name in $ELEM.getAttributeNames() )
$ELEM.getAttribute(name)
```
```python
# [🐍] Python
for name in $ELEM.getAttributeNames():
$ELEM.getAttribute(name)
```
- Modifier le contenu (texte) : `$ELEM.textContent = $STR`
- Modifier une variable CSS : `$ELEM.style.setProperty($CSS_VARNAME, $VALUE)`
- Obtenir la valeur d'une varable CSS: `$ELEM.style.getProperty($CSS_VARNAME)`
💡 Pour modifier dynamiquement la mise en forme d'un élément via Typescript/Brython, il est recommandé de lui ajouter (ou retirer) une classe CSS.
📖 [Plus de méthodes disponibles dans la documentation.](https://developer.mozilla.org/en-US/docs/Web/API/Element)
# Événements
## Bubble vs Capture
Dans les navigateurs, les interactions sont gérées via des événements, qui se composent de 2 phases :
- capture
- bubble
**Capture :** La phase de capture est descendante, elle part du noeud racine et descend vers le noeud cible (target) final. Par exemple, lorsque vous cliquez sur un élément, l'événement de clic va d'abord partir du document, puis par le body. Le navigateur va propager l'événement en se demandant quel fils de l'élément courant est la cible de l'événement, afin de lui transmettre l'événement, puis recommence de manière récursive, l'élément fils cible devenant l'élément courant.
**Bubble :** La phase de buble est montante, elle part du noeud cible (target) final et remonte vers le noeud racine. Si l'événement se propage dans le DOM (`bubble: true`), le navigateur va transmettre l'événement à l'élément père de l'élément courant, puis recommence de manière récursive, l'élément père devant l'élément courant.
## Écouter un événement
```javascript
// [JS] Javascript
function handler(ev) {
// ev.currentTarget : $ELEM
// ev.target : source of the event.
// ev.type : $EVENT_TYPE
// ev.detail : $EVENT_DATA (si CustomEvent, cf plus bas)
// ev.preventDefault() : annuler l'action par défaut du navigateur
// e.g. lorsqu'on clique sur un lien, empêcher d'aller vers la page.
// ev.stopImmediatePropagation() : ne pas appeler les autres
// handleurs pour cet événement.
}
$ELEM.addEventListener($EVENT_TYPE, handler);
// ou
$ELEM.addEventListener($EVENT_TYPE, ev => ... );
```
```python
# [🐍] Python
def handler(ev):
# ev.currentTarget : $ELEM
# ev.target : source of the event.
# ev.type : $EVENT_TYPE
# ev.detail : $EVENT_DATA (si CustomEvent, cf plus bas)
# ev.preventDefault() : annuler l'action par défaut du navigateur
# e.g. lorsqu'on clique sur un lien, empêcher d'aller vers la page.
# ev.stopImmediatePropagation() : ne pas appeler les autres
# handleurs pour cet événement.
$ELEM.addEventListener($EVENT_TYPE, handler)
```
📖 [Plus d'informations dans la documentation.](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
## Écouteur délégué
Il arrive qu'on souhaite écouter des événements sur les descendants d'un élément, qui peuvent être ajoutés, déplacés, supprimés, etc. Le problème est que cela nécessiterait de créer un écouteur pour chaque éléments et de les supprimer/ajouter à chaque modifications du DOM.
Heureusement, il est possible d'utiliser un écouteur délégué, i.e. d'écouter l'événement sur le descendant (nécessite que l'événement soit `bubble`, i.e. se propage dans le DOM).
```javascript
// [JS] Javascript
function handler(ev) {
if( ev.target.matches($CSS_SELECTOR) ) {
// ...
}
}
$ELEM.addEventListener($EVENT_TYPE, handler);
```
```python
# [🐍] Python
def handler(ev):
if ev.target.matches($CSS_SELECTOR):
# ...
$ELEM.addEventListener($EVENT_TYPE, handler)
```
## Créer un événement
```javascript
// [JS] Javascript
$ELEM.dispatchEvent( new Event($EVENT_NAME) );
// ou
$ELEM.dispatchEvent( new CustomEvent($EVENT_NAME, {detail: $EVENT_DATA}) );
```
```python
# [🐍] Python
$ELEM.dispatchEvent( Event.new($EVENT_NAME) )
# ou
$ELEM.dispatchEvent( CustomEvent.new($EVENT_NAME, {"detail": $EVENT_DATA}) )
```
💡 Vous pouvez aussi ajouter, au 2ème argument, l'option `bubble: true` pour faire en sorte que l'événement soit bubble, i.e. se propage dans le DOM (par default `bubble: false`).
# Envoyer une requête REST
```javascript
// [JS] Javascript
async query() {
const anwser = await fetch($URL);
// ou
const answer = await fetch($URL, {method: "POST", body: $PARAMS);
if( ! answer.ok )
throw new Error(`${answer.status}: ${answer.statusText}`);
const json = await answer.json(); // récupérer du JSON
const text = await answer.text(); // récupérer du texte
// autres formats possibles dans la doc.
}
query();
```
```python
# [🐍] Python
async query():
answer = fetch($URL)
# ou
answer = fetch($URL, {"method": "POST", "body": $PARAMS)
if not answer.ok:
raise Error(f"{answer.status}: {answer.statusText}");
json = await answer.json() # récupérer du JSON
text = await answer.text() # récupérer du texte
# autres formats possibles dans la doc.
aio.run( query() ) # [🚩] TODO: Supplier Pierre pour avoir top-level await.
```
📖 [Plus d'informations dans la documentation.](https://developer.mozilla.org/en-US/docs/Web/API/Response)
Pour construire la chaîne de paramètre :
```javascript
// [JS] Javascript
// client
const params = new URLSearchParams();
params.set($NAME, $VALUE)
fetch( `${URL}?${params.toString()}` );
// serveur
const params = new URLSearchParams($STR);
for(let key in params.keys() )
params.get(key); // retourne undefined si pas trouvé.
params.has($NAME); // retourne un booléen
params.get($NAME) ?? $DEFAULT_VALUE; // avec une valeur par défaut
```
```python
# [🐍] Python
# client
params = URLSearchParams.new()
params.set($NAME, $VALUE)
fetch( f"{URL}?{params.toString()}" )
# serveur
params = URLSearchParams.new($STR);
for key in params.keys():
params.get(key) # retourne undefined si pas trouvé.
params.has($NAME) # retourne un booléen
```
📖 [Plus d'informations dans la documentation.](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)