- Aperçu
- Exemple simple
- Détails
- État
- Initialisation de l'état avec amp-state
- Actualisation de l'état
- Mise à jour de l'état avec AMP.setState()
- Modification de l'historique avec AMP.pushState()
- Expressions
- Différences par rapport à JavaScript
- Exemples
- Fonctions sur liste blanche
- Définir des macros avec amp-bind-macro
- Liaisons
- Attributs spécifiques aux éléments
- Débogage
- Avertissements
- Erreurs
- État de débogage
- Annexe
- Spécification de l'élément <amp-state>
- Traitements par lots de requêtes XHR
- Attributs
- Fusion en profondeur avec AMP.setState()
- Supprimer une variable
- Grammaire des expressions
amp-bind
Description
Autoriser la mutation des éléments en réponse aux actions de l'utilisateur ou à des modifications de données au moyen de la liaison de données et de simples expressions de type JS.
Required Scripts
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
Exemples
Ce composant ajoute une interactivité personnalisée en utilisant la liaison de données et des expressions.
Script requis | <script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script> |
Exemples | |
Didacticiels | Créer des pages AMP interactives |
Aperçu
Le composant amp-bind
vous permet d'ajouter une interactivité avec état personnalisée à vos pages AMP au moyen de la liaison de données et d'expressions de type JS.
Exemple simple
Dans l'exemple suivant, le fait d'appuyer sur le bouton remplace le texte "Hello World" de l'élément <p>
par "Hello amp-bind".
<p [text]="'Hello ' + foo">Hello World</p>
<button on="tap:AMP.setState({foo: 'amp-bind'})">Say "Hello amp-bind"</button>
amp-bind
n'évalue pas les expressions lors du chargement de la page. Cela signifie que les éléments visuels doivent être associés à un état par défaut et qu'il ne faut pas utiliser amp-bind
pour l'affichage initial. Comment cela fonctionne-t-il ?
amp-bind
comprend trois composants principaux :
- State : état JSON mutable à l'échelle du document. Dans l'exemple ci-dessus, l'état est vide avant que l'utilisateur appuie sur le bouton. Une fois le bouton enfoncé, l'état devient
{foo: 'amp-bind'}
. - Expressions : expressions de type JavaScript pouvant faire référence à l'état. L'exemple ci-dessus contient une seule expression,
'Hello ' + foo
, qui concatène le littéral de chaîne'Hello '
et la variable d'étatfoo
. Le nombre d'opérandes pouvant être utilisés dans une expression est limité à 100. - Bindings : attributs spéciaux sous la forme
[property]
qui associent la propriété d'un élément à une expression. L'exemple ci-dessus comporte une seule liaison,[text]
, qui met à jour le texte de l'élément<p>
chaque fois que la valeur de l'expression change.
amp-bind
veille tout particulièrement à garantir la vitesse, la sécurité et les performances sur les pages AMP.
Voici un exemple un peu plus complexe
<!-- Store complex nested JSON data in <amp-state> elements. -->
<amp-state id="myAnimals">
<script type="application/json">
{
"dog": {
"imageUrl": "/img/dog.jpg",
"style": "greenBackground"
},
"cat": {
"imageUrl": "/img/cat.jpg",
"style": "redBackground"
}
}
</script>
</amp-state>
<p [text]="'This is a ' + currentAnimal + '.'">Ceci est un chien.</p>
<!-- CSS classes can also be added or removed with [class]. -->
<p class="greenBackground" [class]="myAnimals[currentAnimal].style">
Chaque animal a une couleur de fond différente.
</p>
<!-- Or change an image's src with the [src] binding. -->
<amp-img width="300" height="200" src="/img/dog.jpg" [src]="myAnimals[currentAnimal].imageUrl">
</amp-img>
<button on="tap:AMP.setState({currentAnimal: 'cat'})">Set to Cat</button>
Lorsque l'on appuie sur le bouton :
- L'état est mis à jour avec l'attribut
currentAnimal
défini sur'cat'
. -
Les expressions qui dépendent de
currentAnimal
sont évaluées :'This is a ' + currentAnimal + '.'
=>'This is a cat.'
myAnimals[currentAnimal].style
=>'redBackground'
myAnimals[currentAnimal].imageUrl
=>/img/cat.jpg
-
Les liaisons qui dépendent des expressions modifiées sont mises à jour :
- Le texte du premier élément
<p>
sera "This is a cat." - L'attribut
class
du deuxième élément<p>
sera "redBackground". - L'élément
amp-img
affichera l'image d'un chat.
- Le texte du premier élément
Détails
État
Chaque document AMP qui utilise le composant amp-bind
comprend des données JSON mutables à l'échelle du document, désignées sous le nom d'état.
Initialisation de l'état avec amp-state
L'état d'amp-bind
peut être initialisé avec le composant amp-state
:
<amp-state id="myState">
<script type="application/json">
{
"foo": "bar"
}
</script>
</amp-state>
Les expressions peuvent faire référence à des variables d'état via la syntaxe à points. Dans cet exemple, myState.foo
est évalué sur "bar"
.
- La taille maximale du fichier JSON enfant d'un élément
<amp-state>
est de 100 Ko. - Un élément
<amp-state>
peut également spécifier une URL CORS au lieu d'un script JSON enfant. Pour plus d'informations, reportez-vous à l'Annexe.
Actualisation de l'état
L'action refresh
est compatible avec ce composant. Elle peut être utilisée pour actualiser le contenu de l'état.
<amp-state id="amp-state" ...></amp-state>
<!-- Clicking the button will refresh and refetch the json in amp-state. -->
<button on="tap:amp-state.refresh"></button>
Mise à jour de l'état avec AMP.setState()
L'action AMP.setState()
fusionne un littéral d'objet dans l'état. Par exemple, lorsque l'on appuie sur le bouton ci-dessous, AMP.setState()
effectue une fusion profonde du littéral d'objet avec l'état.
<!-- Like JavaScript, you can reference existing
variables in the values of the object literal. -->
<button on="tap:AMP.setState({foo: 'bar', baz: myAmpState.someVariable})"></button>
En règle générale, la profondeur de fusion maximale des objets imbriqués est de 10 niveaux. Toutes les variables, y compris celles introduites par amp-state
, peuvent être remplacées.
Lorsqu'elle est déclenchée par certains événements, l'action AMP.setState()
peut également accéder aux données relatives aux événements sur la propriété event
.
<!-- The "change" event of this <input> element contains
a "value" variable that can be referenced via "event.value". -->
<input type="range" on="change:AMP.setState({myRangeValue: event.value})">
Modification de l'historique avec AMP.pushState()
L'action AMP.pushState()
est semblable à AMP.setState()
, si ce n'est qu'elle envoie une nouvelle entrée dans la pile d'historique du navigateur. Faire apparaître cette entrée d'historique (en revenant en arrière, par exemple) a pour effet de rétablir la valeur précédente des variables définie par AMP.pushState()
.
Exemple :
<button on="tap:AMP.pushState({foo: '123'})">Set 'foo' to 123</button>
- En appuyant sur le bouton, vous définissez la variable
foo
sur 123 et envoyez une nouvelle entrée d'historique. - En revenant en arrière, vous redéfinissez la variable
foo
sur sa valeur antérieure, à savoir "bar" (ce qui revient à appelerAMP.setState({foo: 'bar'})
.
Expressions
Les expressions sont semblables à JavaScript, avec toutefois quelques différences importantes.
Différences par rapport à JavaScript
- Les expressions peuvent uniquement accéder à l'état du document conteneur.
- Les expressions n'ont pas accès à des données globales telles que
window
oudocument
. - Seuls les opérateurs et les fonctions sur liste blanche peuvent être utilisés.
- En règle générale, les fonctions, classes et boucles personnalisées ne sont pas autorisées. Les fonctions fléchées sont autorisées en tant que paramètres ;
Array.prototype.map
, par exemple. - Les variables non définies et les exceptions array-index-out-of-bounds renvoient la valeur
null
au lieu de renvoyerundefined
ou de générer des erreurs. - Une expression unique est actuellement limitée à 50 opérandes afin d'optimiser les performances. N'hésitez pas à nous contacter si cela s'avère insuffisant dans votre cas.
Pour consulter toute la mise en œuvre et la grammaire complète de l'expression, reportez-vous aux pages bind-expr-impl.jison et bind-expression.js.
Exemples
Toutes les expressions suivantes sont valides :
1 + '1' // 11
1 + (+'1') // 2
!0 // true
null || 'default' // 'default'
Fonctions sur liste blanche
Type d'objet | Fonction(s) | Exemple |
---|---|---|
Tableau 1 | concat filter includes indexOf join lastIndexOf map reduce slice some sort (not-in-place)splice (not-in-place) | // Returns [1, 2, 3]. [3, 2, 1].sort() // Returns [1, 3, 5]. [1, 2, 3].map((x, i) => x + i) // Returns 6. [1, 2, 3].reduce((x, y) => x + y) |
Nombre | toExponential toFixed toPrecision toString | // Returns 3. (3.14).toFixed() // Returns '3.14'. (3.14).toString() |
Chaîne | charAt charCodeAt concat indexOf lastIndexOf slice split substr substring toLowerCase toUpperCase | // Returns 'abcdef'. abc'.concat('def') |
Fonctions mathématiques 2 | abs ceil floor max min random round sign | // Returns 1. abs(-1) |
Objet 2 | keys values | // Returns ['a', 'b']. keys({a: 1, b: 2}) // Returns [1, 2]. values({a: 1, b: 2} |
Global 2 | encodeURI encodeURIComponent | // Returns 'Hello%20world'. encodeURIComponent('Hello world') |
1 Les fonctions fléchées à un seul paramètre ne peuvent pas contenir de parenthèses. Utilisez, par exemple, x => x + 1
au lieu de (x) => x + 1
. En outre, sort()
et splice()
renvoient des copies modifiées au lieu de s'exécuter sur place.
2 Les fonctions statiques sont dépourvues d'espace de noms ; utilisez, par exemple, abs(-1)
au lieu de Math.abs(-1)
.
Définir des macros avec amp-bind-macro
Les fragments d'expression amp-bind
peuvent être réutilisés en définissant un élément amp-bind-macro
. L'élément amp-bind-macro
vous permet de définir une expression qui utilise zéro ou plusieurs arguments et fait référence à l'état actuel. Une macro peut être appelée comme une fonction en référençant sa valeur d'attribut id
depuis n'importe quel point du document.
<amp-bind-macro id="circleArea" arguments="radius" expression="3.14 * radius * radius"></amp-bind-macro>
<div>
L'aire du cercle est de <span [text]="circleArea(myCircle.radius)">0</span>.
</div>
Une macro peut également en appeler d'autres qui sont définies avant elle. En revanche, elle ne peut pas s'appeler de manière récursive.
Liaisons
Une liaison est un attribut spécial sous la forme [property]
qui associe la propriété d'un élément à une expression. Une autre syntaxe compatible avec XML peut également être utilisée sous la forme data-amp-bind-property
.
Lorsque l'état change, les expressions sont réévaluées et les propriétés des éléments liés sont mises à jour avec les nouveaux résultats d'expression.
amp-bind
accepte les liaisons de données sur quatre types d'état d'élément :
Type | Attribut(s) | Détails |
---|---|---|
Node.textContent | [text] | Compatible avec la plupart des éléments textuels. |
Classes CSS | [class] | Le résultat de l'expression doit être une chaîne délimitée par des espaces. |
Attribut hidden | [hidden] | Il doit s'agir d'une expression booléenne. |
Taille des éléments AMP | [width] [height] | Modifie la largeur et/ou la hauteur de l'élément AMP. |
Attributs spécifiques aux éléments | Divers |
Remarques sur les liaisons :
- Pour des raisons de sécurité, la liaison vers
innerHTML
n'est pas autorisée. - Les valeurs qui présentent un risque sont effacées de toutes les liaisons d'attribut (
javascript:
, par exemple). - Les résultats des expressions booléennes font varier les attributs booléens. Prenons l'exemple de
<amp-video [controls]="expr"...>
. Lorsqueexpr
est défini surtrue
, l'attributcontrols
est associé à l'élément<amp-video>
. Lorsqueexpr
est défini surfalse
, l'attributcontrols
est supprimé. - L'utilisation de crochets (
[
et]
) dans les noms d'attribut peut poser problème lors de la rédaction de code XML (XHTML, JSX, etc.) ou de l'écriture d'attributs au moyen d'API DOM. Dans ce cas, utilisez la syntaxedata-amp-bind-x="foo"
au lieu de[x]="foo"
.
Attributs spécifiques aux éléments
Seule la liaison aux composants et attributs suivants est autorisée :
Élément | Attribut(s) | Comportement |
---|---|---|
<amp-brightcove> | [data-account] [data-embed] [data-player] [data-player-id] [data-playlist-id] [data-video-id] | Modifie la vidéo Brightcove affichée. |
<amp-carousel type=slides> | [slide] * | Modifie l'index des diapositives en cours d'affichage. Voir un exemple. |
<amp-date-picker> | [min] [max] | Définit la date la plus ancienne pouvant être sélectionnée. Définit la date la plus proche pouvant être sélectionnée. |
<amp-google-document-embed> | [src] [title] | Affiche le document au niveau de l'URL mise à jour. Modifie le titre du document. |
<amp-iframe> | [src] | Modifie l'URL source de l'iFrame. |
<amp-img> | [alt] [attribution] [src] [srcset] | En cas de liaison à [src] , veillez également à lier [srcset] pour que la liaison fonctionne sur le cache.Voir les attributs amp-img correspondants. |
<amp-lightbox> | [open] * | Active/désactive l'affichage du mode Lightbox. Conseil : Utilisez on="lightboxClose: AMP.setState(...)" pour mettre à jour les variables lorsque le mode Lightbox est désactivé. |
<amp-list> | [src] | Si l'expression est une chaîne, cet élément récupère et affiche le code JSON depuis l'URL de la chaîne. Si l'expression est un objet ou un tableau, cet élément affiche les données d'expression. |
<amp-selector> | [selected] *[disabled] | Modifie le ou les éléments enfants sélectionnés qui sont identifiés par leurs valeurs d'attribut option . Une liste de valeurs séparées par des virgules est acceptée pour sélectionner plusieurs éléments. Voir un exemple. |
<amp-state> | [src] | Récupère le code JSON de la nouvelle URL et le fusionne dans l'état existant. Notez que la mise à jour suivante ignorera les éléments <amp-state> afin d'éviter les cycles. |
<amp-video> | [alt] [attribution] [controls] [loop] [poster] [preload] [src] | Voir les attributs amp-video correspondants. |
<amp-youtube> | [data-videoid] | Change la vidéo YouTube affichée. |
<a> | [href] | Modifie le lien. |
<button> | [disabled] [type] [value] | Voir les attributs button correspondants. |
<details> | [open] | Voir les attributs details correspondants. |
<fieldset> | [disabled] | Active ou désactive le jeu de champs. |
<image> | [xlink:href] | Voir les attributs image correspondants. |
<input> | [accept] [accessKey] [autocomplete] [checked] [disabled] [height] [inputmode] [max] [maxlength] [min] [minlength] [multiple] [pattern] [placeholder] [readonly] [required] [selectiondirection] [size] [spellcheck] [step] [type] [value] [width] | Voir les attributs input correspondants. |
<option> | [disabled] [label] [selected] [value] | Voir les attributs option correspondants. |
<optgroup> | [disabled] [label] | Voir les attributs optgroup correspondants. |
<select> | [autofocus] [disabled] [multiple] [required] [size] | Voir les attributs select correspondants. |
<source> | [src] [type] | Voir les attributs source correspondants. |
<track> | [label] [src] [srclang] | Voir les attributs track correspondants. |
<textarea> | [autocomplete] [autofocus] [cols] [disabled] [maxlength] [minlength] [placeholder] [readonly] [required] [rows] [selectiondirection] [selectionend] [selectionstart] [spellcheck] [wrap] | Voir les attributs textarea correspondants. |
* Désigne les attributs pouvant être liés auxquels ne correspond aucun élément qui ne peut pas l'être.
Débogage
Effectuez un test en mode de développement (avec le fragment d'URL #development=1
) pour mettre en évidence les avertissements et les erreurs générés pendant le développement, et pour accéder à des fonctions de débogage spéciales.
Avertissements
En mode de développement, amp-bind
émet un avertissement lorsque la valeur par défaut d'un attribut lié ne correspond pas au résultat initial de l'expression équivalente. Cela permet d'éviter les mutations indésirables consécutives aux modifications apportées à d'autres variables d'état. Par exemple :
<!-- The element's default class value ('def') doesn't match the
expression result for [class] ('abc'),
so a warning will be issued in development mode. -->
<p class="def" [class]="'abc'"></p>
En mode de développement, amp-bind
émet également un avertissement lors du déréférencement de variables ou de propriétés non définies. Cela permet, en outre, d'éviter les mutations indésirables dues aux résultats d'expression null
. Par exemple :
<amp-state id="myAmpState">
<script type="application/json">
{ "foo": 123 }
</script>
</amp-state></p>
<!-- The amp-state#myAmpState does not have a `bar` variable, so a warning
will be issued in development mode. -->
<p [text]="myAmpState.bar">Texte d'espace réservé.</p>
Erreurs
Plusieurs types d'erreurs d'exécution peuvent se produire lors de l'utilisation du composant amp-bind
.
Type | Message | Suggestion |
---|---|---|
Liaison incorrecte | Binding to [someBogusAttribute] on <P> is not allowed. | Utilisez uniquement des liaisons sur liste blanche. |
Erreur de syntaxe | Expression compilation error in... | Vérifiez que l'expression ne contient pas de fautes de frappe. |
Fonctions ne figurant pas sur liste blanche | alert is not a supported function. | Utilisez uniquement des fonctions sur liste blanche. |
Résultat expurgé | "javascript:alert(1)" is not a valid result for [href]. | Évitez les expressions ou protocoles d'URL interdits qui entraîneraient l'échec de validateur AMP. |
Non-respect de la stratégie de sécurité du contenu (CSP) | Refused to create a worker from 'blob:...' because it violates the following Content Security Policy directive... | Ajoutez default-src blob: à la stratégie de sécurité du contenu (CSP) de votre origine. amp-bind délègue les tâches fastidieuses à un web worker dédié pour garantir un niveau de performances élevé. |
État de débogage
Utilisez AMP.printState()
pour imprimer l'état actuel de la console.
Annexe
Spécification de l'élément <amp-state>
Un élément amp-state
peut être composé d'un élément <script>
enfant OU d'un attribut src
contenant une URL CORS vers un point de terminaison JSON distant, mais pas des deux.
<amp-state id="myLocalState">
<script type="application/json">
{
"foo": "bar"
}
</script>
</amp-state></p>
<p><amp-state id="myRemoteState" src="https://data.com/articles.json">
</amp-state>
Traitements par lots de requêtes XHR
AMP regroupe les requêtes XHR (XMLHttpRequest) dans des points de terminaison JSON. En d'autres termes, vous pouvez utiliser une seule requête de données JSON comme source de données pour plusieurs consommateurs (plusieurs éléments amp-state
, par exemple) sur une page AMP. Supposons que l'élément amp-state
adresse une requête XHR à un point de terminaison. Dans ce cas, lorsque la requête XHR sera en cours, les requêtes XHR ultérieures adressées au même point de terminaison ne se déclencheront pas et renverront, à la place, les résultats à partir de la première requête XHR.
Attributs
src | URL du point de terminaison distant qui renvoie le fichier JSON qui mettra à jour cet élément amp-state . Il doit s'agir d'un service HTTP CORS. L'attribut src autorise toutes les substitutions de variables d'URL standards. Pour plus d'informations, consultez le Guide des substitutions. Le point de terminaison doit mettre en œuvre les exigences énoncées dans la spécification Requêtes CORS dans AMP.
|
credentials (facultatif) | Définit une option credentials telle qu'elle est spécifiée par l'API Fetch.
include . Si cette valeur est définie, la réponse doit respecter les consignes de sécurité CORS dans AMP. |
Fusion en profondeur avec AMP.setState()
Lorsque l'action AMP.setState()
est appelée, amp-bind
fusionne en profondeur le littéral d'objet fourni avec l'état actuel. Toutes les variables du littéral d'objet sont écrites directement dans l'état, à l'exception des objets imbriqués, qui sont fusionnés de manière récursive. Les primitives et les tableaux qui se trouvent dans l'état sont toujours écrasés par les variables portant le même nom dans le littéral d'objet.
Prenons l'exemple suivant :
{
<!-- State is empty -->
}
<button on="tap:AMP.setState({employee: {name: 'John Smith', age: 47, vehicle: 'Car'}})"...></button>
<button on="tap:AMP.setState({employee: {age: 64}})"...></button>
Lorsque vous appuyez sur le premier bouton, l'état devient :
{
employee: {
name: 'John Smith',
age: 47,
vehicle: 'Car',
}
}
Lorsque vous appuyez sur le deuxième bouton, amp-bind
fusionne de manière récursive l'argument de littéral de l'objet, {employee: {age: 64}}
, dans l'état existant.
{
employee: {
name: 'John Smith',
age: 64,
vehicle: 'Car',
}
}
employee.age
a été mis à jour, mais les clés employee.name
et employee.vehicle
n'ont pas changé.
Notez que le composant amp-bind
génère une erreur si vous appelez AMP.setState()
avec un littéral d'objet contenant des références circulaires.
Supprimer une variable
Pour supprimer une variable d'état, définissez sa valeur sur null
dans AMP.setState()
. En commençant par l'état de l'exemple précédent, si vous appuyez sur :
<button on="tap:AMP.setState({employee: {vehicle: null}})"...></button>
L'état est remplacé par :
{
employee: {
name: 'John Smith',
age: 48,
}
}
De même, si vous appuyez sur :
<button on="tap:AMP.setState({employee: null})"...></button>
L'état est remplacé par :
{
<!-- State is empty -->
}
Grammaire des expressions
Grammaire de type BNF pour les expressions amp-bind
:
expr:
operation
| invocation
| member_access
| '(' expr ')'
| variable
| literal
operation:
!' expr
| '-' expr
| '+' expr
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| expr '%' expr
| expr '&&' expr
| expr '||' expr
| expr '<=' expr
| expr '<' expr
| expr '>=' expr
| expr '>;' expr
| expr '!=' expr
| expr '==' expr
| expr '?' expr ':' expr
invocation:
expr '.' NAME args
args:
(' ')'
| '(' array ')'
;
member_access:
expr member
;
member:
.' NAME
| '[' expr ']'
variable:
NAME
;
literal:
STRING
| NUMBER
| TRUE
| FALSE
| NULL
| object_literal
| array_literal
array_literal:
[' ']'
| '[' array ']'
array:
expr
| array ',' expr
object_literal:
{' '}'
| '{' object '}'
object:
key_value
| object ',' key_value
key_value:
expr ':' expr
Vous avez lu ce document une douzaine de fois mais il ne répond pas à toutes vos questions ? D'autres personnes ont peut-être eu le même sentiment. Contactez-les sur Stack Overflow.
Se rendre sur Stack Overflow Vous avez trouvé un bug ou une fonctionnalité manquante ?Le projet AMP encourage fortement votre participation et vos contributions ! Nous espérons que vous deviendrez un membre régulier de notre communauté open source, mais nous serons également ravis de recevoir des contributions ponctuelles concernant les questions qui vous intéressent particulièrement.
Se rendre sur GitHub