AMP

amp-bind

Aggiunge interattività personalizzata tramite associazione di dati ed espressioni.

Script obbligatorio
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
Esempi
Tutorial Creare pagine AMP interattive

Panoramica

Il componente amp-bind ti permette di aggiungere dell'interattività stateful personalizzata alle tue pagine AMP tramite associazione di dati ed espressioni simili a JavaScript.

Guarda questo video per un'introduzione ad amp-bind.

Un esempio semplice

Nell'esempio seguente, toccando il pulsante il testo dell'elemento <p> cambia da "Hello World" a "Hello amp-bind".

<p [text]="'Hello ' + foo">Hello World</p>

<button on="tap:AMP.setState({foo: &#39;amp-bind&#39;})">Say "Hello amp-bind"</button>

per prestazioni ottimali e per evitare il rischio di salti inaspettati dei contenuti, amp-bind non valuta le espressioni al caricamento della pagina. Ciò significa che gli elementi visivi dovrebbero avere uno stato predefinito e non fare affidamento su amp-bind per la visualizzazione iniziale.

Come funziona?

amp-bind ha tre componenti principali:

  1. Stato. Uno stato JSON mutevole orientato al documento. Nell'esempio precedente, state è vuoto prima che l'utente tocchi il pulsante. Dopo aver toccato il pulsante, state diventa {foo: 'amp-bind'}.
  2. Espressioni. Espressioni simili a JavaScript che possono fare riferimento a state. L'esempio precedente contiene una sola espressione, 'Hello ' + foo, che concatena il valore letterale della stringa 'Hello ' e la variabile di stato foo. All'interno di un'espressione possono essere utilizzati un massimo di 100 operandi.
  3. Associazioni. Attributi speciali del modulo [property] che collegano la proprietà di un elemento a una expression. L'esempio precedente contiene una sola associazione, [text], che aggiorna il testo dell'elemento <p> ogni volta che il valore dell'espressione cambia.

amp-bind fa tutto il possibile per garantire velocità, sicurezza e prestazioni nelle pagine AMP.

Un esempio un po' più complesso

<!-- 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 + '.'">This is a dog.</p>
<!-- CSS classes can also be added or removed with [class]. -->
<p class="greenBackground" [class]="myAnimals[currentAnimal].style">
  Each animal has a different background color.
</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>

<p><button on="tap:AMP.setState({currentAnimal: &#39;cat&#39;})">Set to Cat</button>

Quando viene premuto il pulsante:

  1. Lo stato viene aggiornato con currentAnimal, definito come 'cat'.
  2. Le espressioni che dipendono da currentAnimal vengono valutate:

    • 'This is a ' + currentAnimal + '.' => 'This is a cat.'
    • myAnimals[currentAnimal].style => 'redBackground'
    • myAnimals[currentAnimal].imageUrl => /img/cat.jpg
  3. Le associazioni che dipendono dalle espressioni modificate vengono aggiornate:

    • Il testo del primo elemento <p> sarà "This is a cat."
    • L'attributo class del secondo elemento <p> sarà "redBackground".
    • L'elemento amp-img mostrerà l'immagine di un gatto.

prova la demo dal vivo di questo esempio con annotazioni del codice.

Dettagli

Stato

Tutti i documenti AMP che utilizzano amp-bind presentano dei dati JSON mutevoli orientati al documento, detti state.

Inizializzare lo stato con amp-state

Lo stato di amp-bind può essere inizializzato con il componente amp-state:

<amp-state id="myState">
  <script type="application/json">
    {
      "foo": "bar"
      }
  </script>
</amp-state>

Le espressioni possono fare riferimento a variabili di stato tramite la sintassi dot. In questo esempio, myState.foo avrà come risultato "bar".

  • Un elemento secondario JSON di <amp-state> ha una dimensione massima di 100 kB.
  • Un elemento <amp-state> può anche specificare un URL CORS anziché uno script JSON secondario. Per ulteriori dettagli, consulta l'appendice.

Aggiornare lo stato

Questo componente supporta l'azione refresh, che può essere utilizzata per aggiornare i contenuti dello stato.

<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>

Aggiornare lo stato con AMP.setState()

L'azione AMP.setState() unisce un valore letterale oggetto allo stato. Ad esempio, quando viene premuto il pulsante in basso, AMP.setState() unirà forzatamente il valore letterale oggetto allo stato.

<!-- 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>

In generale, gli oggetti nidificati saranno uniti fino a una profondità massima di 10. Tutte le variabili, incluse quelle introdotte da amp-state, possono essere sostituite.

Quando attivato da certi eventi, AMP.setState() può anche accedere ai dati correlati agli eventi nella proprietà 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})">

Modificare la cronologia con AMP.pushState()

L'azione AMP.pushState() è simile ad AMP.setState(), ma in aggiunta inserisce una nuova voce nell'elenco della cronologia di navigazione. Accedendo a questa voce della cronologia, ad esempio, tornando indietro, viene ripristinato il valore precedente delle variabili impostate da AMP.pushState().

Ad esempio:

<button on="tap:AMP.pushState({foo: '123'})">Set 'foo' to 123</button>
  • Se tocchi il pulsante, la variabile foo sarà impostata su 123 e si creerà una nuova voce della cronologia.
  • Se torni indietro, foo verrà ripristinato al suo valore precedente, "bar" (equivale a chiamare AMP.setState({foo: 'bar'}).

Espressioni

Le espressioni sono simili a JavaScript, con alcune differenze importanti.

Differenze da JavaScript

  • Le espressioni possono accedere solo allo stato del documento che le contiene.
  • Le espressioni non hanno accesso a elementi globali come window o document.
  • Puoi utilizzare solo gli operatori e le funzioni consentiti.
  • I loop, le classi e le funzioni personalizzate in genere non sono consentiti. Le funzioni a freccia sono consentite come parametri, ad esempio, Array.prototype.map.
  • Le variabili non definite e l'indice della matrice fuori intervallo restituiscono null anziché undefined o degli errori.
  • Per garantire buone prestazioni, in una singola espressione possono attualmente essere presenti un massimo di 50 operandi. Nel caso in cui siano insufficienti per il tuo caso d'uso, non esitare a contattarci.

La grammatica completa e l'implementazione delle espressioni sono riportate in bind-expr-impl.jison e bind-expression.js.

Esempi

Di seguito sono riportate tutte le espressioni valide:

1 + '1'           // 11
1 + (+'1')        // 2
!0                // true
null || 'default' // 'default'

Funzioni consentite

Tipo di oggetto Funzioni Esempio
Array1 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)
Number toExponential
toFixed
toPrecision
toString
// Returns 3.
                (3.14).toFixed()
// Returns '3.14'.
                  (3.14).toString()
String charAt
charCodeAt
concat
indexOf
lastIndexOf
slice
split
substr
substring
toLowerCase
toUpperCase
// Returns 'abcdef'.
                      abc'.concat('def')
Math2 abs
ceil
floor
max
min
random
round
sign
// Returns 1.
                          abs(-1)
Object2 keys
values
// Returns ['a', 'b'].
                            keys({a: 1, b: 2})
// Returns [1, 2].
                              values({a: 1, b: 2}
Global2 encodeURI
encodeURIComponent
// Returns 'Hello%20world'.
                                encodeURIComponent('Hello world')

1Le funzioni a freccia a parametro singolo non possono presentare parentesi. Ad esempio, utilizza x => x + 1 anziché (x) => x + 1. Inoltre, sort() e splice() restituiscono copie modificate anziché operare sul posto

2Le funzioni statiche non dispongono di spazio dei nomi. Ad esempio, utilizza abs(-1) anziché Math.abs(-1).

Definire macro con amp-bind-macro

I frammenti dell'espressione amp-bind possono essere riutilizzati definendo una amp-bind-macro. L'elemento amp-bind-macro ti permette di definire un'espressione che accetta zero o più argomenti e fa riferimento allo stato corrente. Una macro può essere richiamata come una funzione facendo riferimento al valore del suo attributo id in qualunque punto del tuo documento.

<amp-bind-macro id="circleArea" arguments="radius" expression="3.14 * radius * radius"></amp-bind-macro></p>

<div>
  The circle has an area of <span [text]="circleArea(myCircle.radius)">0</span>.
</div>

Una macro può anche chiamare altre macro definite prima di essa. Una macro non può chiamare se stessa in modo ricorsivo.

Associazioni

Un'associazione è un attributo speciale del modulo [property] che collega la proprietà di un elemento a un'espressione. Puoi anche utilizzare una sintassi alternativa compatibile con XML per mezzo di data-amp-bind-property.

Quando lo stato cambia, le espressioni vengono rivalutate e le proprietà degli elementi associati vengono aggiornate con i nuovi risultati delle espressioni.

amp-bind supporta le associazioni di dati in quattro tipi di stati dell'elemento:

Tipo Attributi Dettagli
Node.textContent [text] Supportato dalla maggior parte degli elementi di testo.
Classi CSS [class] Il risultato dell'espressione deve essere una stringa delimitata da spazi.
L'attributo hidden [hidden] Deve essere un'espressione booleana.
Dimensione degli elementi AMP [width]
[height]
Modifica la larghezza e/o l'altezza dell'elemento AMP.
Attributi specifici degli elementi Vari

Note sulle associazioni:

  • Per motivi di sicurezza, le associazioni a innerHTML non sono consentite.
  • Tutte le associazioni degli attributi sono bonificate da valori non sicuri (ad esempio, javascript:).
  • I risultati delle espressioni booleane attivano o disattivano attributi booleani. Ad esempio, <amp-video [controls]="expr"...>. Quando expr ha come risultato true, l'elemento <amp-video> ha l'attributo controls. Quando expr ha come risultato false, l'attributo controls viene rimosso.
  • I caratteri di parentesi quadre [ e ] nei nomi degli attributi possono essere problematici durante la scrittura di XML (ad esempio, XHTML, JSX) o di attributi tramite API DOM. In questi casi, utilizza la sintassi alternativa data-amp-bind-x="foo" anziché [x]="foo".

Attributi specifici degli elementi

È consentita l'associazione solo ai seguenti componenti e attributi:

Componente Attributi Comportamento
<amp-brightcove> [data-account]
[data-embed]
[data-player]
[data-player-id]
[data-playlist-id]
[data-video-id]
Modifica il video Brightcove visualizzato.
<amp-carousel type=slides> [slide]* Modifica l'indice della diapositiva attualmente visualizzata. Vedi un esempio.
<amp-date-picker> [min]
[max]
Imposta la data selezionabile meno recente.
Imposta la data selezionabile più recente.
<amp-google-document-embed> [src]
[title]
Mostra il documento all'URL aggiornato.
Modifica il titolo del documento.
<amp-iframe> [src] Modifica l'URL di origine dell'iframe.
<amp-img> [alt]
[attribution]
[src]
[srcset]
Quando effettui un'associazione a [src], assicurati di associare anche a [srcset] in modo che l'associazione funzioni su cache.
Vedi gli attributi amp-img corrispondenti.
<amp-lightbox> [open]* Attiva o disattiva la visualizzazione della lightbox. Suggerimento: utilizza on="lightboxClose: AMP.setState(...)" per aggiornare le variabili quando la lightbox è chiusa.
<amp-list> [src] Se l'espressione è una stringa, recupera e mostra JSON dall'URL della stringa. Se l'espressione è un oggetto o un array, mostra i dati dell'espressione.
<amp-selector> [selected]*
[disabled]
Modifica gli elementi secondari attualmente selezionati
identificati dai loro valori attributo option. Supporta un elenco di valori separati da virgola per la selezione multipla. Vedi un esempio.
<amp-state> [src] Recupera JSON dal nuovo URL e lo unisce allo stato esistente. Tieni presente che il successivo aggiornamento ignorerà gli elementi <amp-state> per impedire i cicli.
<amp-video> [alt]
[attribution]
[controls]
[loop]
[poster]
[preload]
[src]
Vedi gli attributi amp-video corrispondenti.
<amp-youtube> [data-videoid] Cambia il video di YouTube visualizzato.
<a> [href] Cambia il link.
<button> [disabled]
[type]
[value]
Vedi gli attributi button corrispondenti.
<details> [open] Vedi gli attributi details corrispondenti.
<fieldset> [disabled] Attiva o disattiva fieldset.
<image> [xlink:href]
Vedi gli attributi image corrispondenti.
<input> [accept]
[accessKey]
[autocomplete]
[checked]
[disabled]
[height]
[inputmode]
[max]
[maxlength]
[min]
[minlength]
[multiple]
[pattern]
[placeholder]
[readonly]
[required]
[selectiondirection]
[size]
[spellcheck]
[step]
[type]
[value]
[width]
Vedi gli attributi input corrispondenti.
<option> [disabled]
[label]
[selected]
[value]
Vedi gli attributi options corrispondenti.
<optgroup> [disabled]
[label]
Vedi gli attributi optgroup corrispondenti.
<select> [autofocus]
[disabled]
[multiple]
[required]
[size]
Vedi gli attributi select corrispondenti.
<source> [src]
[type]
Vedi gli attributi source corrispondenti.
<track> [label]
[src]
[srclang]
Vedi gli attributi track corrispondenti.
<textarea> [autocomplete]
[autofocus]
[cols]
[disabled]
[maxlength]
[minlength]
[placeholder]
[readonly]
[required]
[rows]
[selectiondirection]
[selectionend]
[selectionstart]
[spellcheck]
[wrap]
Vedi gli attributi textarea corrispondenti.

*Denota degli attributi associabili che non possiedono una controparte non associabile.

Debug

Esegui dei test in modalità sviluppatore (con il frammento dell'URL #development=1) per identificare avvisi ed errori durante lo sviluppo e per accedere a funzioni speciali di debug.

Avvisi

In modalità sviluppatore, amp-bind genererà un avviso quando il valore predefinito di un attributo associato non coincide con il risultato iniziale dell'espressione corrispondente. Ciò aiuta a prevenire cambiamenti non intenzionali causati da modifiche in altre variabili di stato. Ad esempio:

<!-- Il valore di classe predefinito dell'elemento ('def') non corrisponde al risultato dell'espressione [class] ('abc'),
quindi verrà generato un avviso in modalità sviluppatore. -->

<p class="def" [class]="'abc'"></p>

In modalità sviluppatore, amp-bind genererà un avviso anche quando viene tolto il riferimento a variabili o proprietà non definite. Ciò aiuta anche a prevenire cambiamenti non intenzionali causati dai risultati null delle espressioni. Ad esempio:

<amp-state id="myAmpState">
  <script type="application/json">
    { "foo": 123 }
</script>
</amp-state>

<!-- The amp-state#myAmpState does not have a `bar` variable, so a warning
  will be issued in development mode. -->
<p [text]="myAmpState.bar">Some placeholder text.</p>

Errori

Esistono diversi tipi di errori di runtime che possono verificarsi quando si utilizza amp-bind.

Tipo Messaggio Suggerimento
Associazione non valida L'associazione a [someBogusAttribute] su <P> non è consentita. Utilizza solo associazioni consentite.
Errore di sintassi Errore nella compilazione dell'espressione in... Controlla che l'espressione non presenti errori ortografici.
Funzioni non consentite alert non è una funzione supportata. Utilizza solo le funzioni consentite.
Risultato bonificato "javascript:alert(1)" non è un risultato valido per [href]. Evita espressioni o protocolli URL non accettati dallo strumento di convalida AMP.
Violazione CSP Impossibile creare un worker da 'blob:...' perché viola la seguente direttiva relativa alle norme sulla sicurezza dei contenuti... Aggiungi default-src blob: alle norme sulla sicurezza dei contenuti della tua origine. amp-bind delega la porzione più impegnativa dell'elaborazione a un web worker dedicato per garantire buone prestazioni.

Stato di debug

Utilizza AMP.printState() per visualizzare lo stato corrente sulla console.

Appendice

Specifica di <amp-state>

Un elemento amp-state può contenere un elemento secondario <script> O un attributo src che contiene a sua volta un URL CORS per un endpoint JSON, ma non entrambi.

<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>

Gruppi di XHR

AMP raggruppa le XMLHttpRequests (XHR) negli endpoint JSON, ovvero puoi utilizzare una singola richiesta di dati JSON come origine dati per più consumatori (ad esempio, più elementi amp-state) in una pagina AMP. Ad esempio, se l'elemento amp-state crea un XHR per un endpoint, mentre l'XHR è in esecuzione tutti i successivi XHR per lo stesso endpoint non si attiveranno e restituiranno invece i risultati del primo XHR.

Attributi

src L'URL dell'endpoint remoto che restituirà il JSON per aggiornare questo amp-state. Deve essere un servizio HTTP CORS. L'attributo src consente tutte le sostituzioni di variabili URL standard. Per ulteriori informazioni, consulta la Guida alle sostituzioni.
L'endpoint deve implementare i requisiti specificati nella specifica Richieste CORS in AMP.
credentials (facoltativo) Definisce un'opzione credentials come specificato dall'API Fetch.
  • Valori supportati: `omit`, `include`
  • Impostazione predefinita: `omit`
Per inviare le credenziali, trasmetti il valore di include. Se questo valore è impostato, la risposta deve rispettare le norme sulla sicurezza AMP CORS.

Deep-merge con AMP.setState()

Quando AMP.setState() viene chiamato, amp-bind effettua il deep-merge il valore letterale oggetto fornito con lo stato corrente. Tutte le variabili del valore letterale oggetto sono scritte direttamente nello stato, eccetto per gli oggetti nidificati, che vengono uniti in modo ricorsivo. Le primitive e gli array nello stato vengono sempre sostituite da variabili con lo stesso nome nel valore letterale oggetto.

Considera l'esempio seguente:

{
  <!-- 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>

Quando viene premuto il primo pulsante, lo stato cambia in:

{
  employee: {
    name: 'John Smith',
    age: 47,
    vehicle: 'Car',
    }
  }

Quando viene premuto il secondo pulsante, amp-bind unisce in modo ricorsivo l'argomento letterale oggetto {employee: {age: 64}} nello stato esistente.

{
  employee: {
    name: 'John Smith',
    age: 64,
    vehicle: 'Car',
    }
  }

employee.age è stato aggiornato; tuttavia, le chiavi employee.name ed employee.vehicle non sono cambiate.

Tieni presente che amp-bind genererà un errore se chiami AMP.setState() con un valore letterale oggetto che contiene riferimenti circolari.

Rimuovere una variabile

Per rimuovere una variabile di stato esistente, imposta il suo valore su null in AMP.setState(). Partendo dallo stato dell'esempio precedente, premi:

<button on="tap:AMP.setState({employee: {vehicle: null}})"...></button>

Lo stato verrà modificato in:

{
  employee: {
    name: 'John Smith',
    age: 48,
    }
  }

Analogamente:

<button on="tap:AMP.setState({employee: null})"...></button>

Lo stato verrà modificato in:

{
  <!-- State is empty -->
  }

Grammatica delle espressioni

La grammatica simile a BNF per le espressioni 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 '&amp;&amp;' expr
    | expr '||' expr
    | expr '<=' expr
    | expr '<' expr
    | expr '>=' expr
    | expr '>' expr
    | expr '!=' expr
    | expr '==' expr
    | expr '?' expr ':' expr

  invocation:
      expr '.' NAME args

    args:
        (' ')'
        | '(' array ')'
        ;

      <p>member_access:
          expr member
          ;

        <p>member:
            .' NAME
            | '[' expr ']'

          <p>variable:
              NAME
              ;

            literal:
                STRING
                | NUMBER
                | TRUE
                | FALSE
                | NULL
                | object_literal
                | array_literal

              array_literal:
                  [' ']'
                  | '[' array ']'

                array:
                    expr
                    | array ',' expr

                  object_literal:
                      {' '}'
                      | '{' object '}'</p>

                    object:
                        key_value
                        | object ',' key_value</p>

                      key_value:
                          expr ':' expr
Ti servono altre informazioni?

Hai letto questo documento decine di volte ma non risponde a tutte le tue domande? Forse ci sono altre persone col tuo stesso problema: entra in contatto con loro su Stack Overflow.

Vai a Stack Overflow
Hai trovato un bug o una funzione mancante?

Il progetto AMP invita tutti a partecipare e dare il proprio contributo! Ci auguriamo che tu possa partecipare regolarmente alla nostra community open source, ma saremo anche lieti di ricevere eventuali contributi una-tantum sulle questioni che ti interessano.

Vai a GitHub