AMP

amp-bind

Añade interactividad personalizada utilizando data bindings y expresiones.

Secuencia de comandos obligatoria
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
Ejemplos
Tutoriales Crear páginas de AMP interactivas

Descripción general

El componente amp-bind te permite añadir interactividad personalizada con reconocimiento de estado a tus páginas de AMP mediante el uso de data binding y expresiones similares a JS.

Echa un vistazo a este vídeo para conocer los aspectos básicos de amp-bind.

Un ejemplo muy sencillo

En el siguiente ejemplo, si tocas el botón, el texto del elemento <p> pasará de ser "Hello World" a "Hello amp-bind".

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

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

Por cuestiones de rendimiento y para evitar que el contenido se desplace de forma inesperada, amp-bind no evalúa las expresiones al cargar la página. Esto quiere decir que los elementos visuales deben tener un estado predeterminado y no depender de amp-bind para el renderizado inicial.

¿Cómo funciona?

amp-bind tiene tres componentes principales:

  1. Estado: un estado JSON mutable que afecta al documento. En el ejemplo que aparece más arriba, el estado está vacío antes de tocar el botón. Después de tocar el botón, el estado es {foo: 'amp-bind'}.
  2. Expresiones: son expresiones similares a JavaScript que pueden hacer referencia al estado. El ejemplo que aparece más arriba tiene una única expresión, 'Hello ' + foo, que concatena el literal de cadena 'Hello ' y la variable de estado foo. Una expresión puede contener un máximo de 100 operandos.
  3. Bindings: son atributos especiales de la forma [property] que enlazan la propiedad de un elemento con una expresión. El ejemplo anterior tiene un único binding, [text], que actualiza el texto del elemento <p> cada vez que cambia el valor de la expresión.

amp-bind pone un especial énfasis en garantizar la velocidad, la seguridad y el rendimiento de las páginas de AMP.

Veamos un ejemplo ligeramente más complejo:

<!-- Se pueden almacenar datos JSON complejos anidados en elementos <amp-state> -->
 <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 + '.'">Esto es un perro.</p>

<!-- También se pueden añadir o eliminar clases de CSS mediante [class]. -->
<p class="greenBackground" [class]="myAnimals[currentAnimal].style">
  Cada animal tiene un color de fondo diferente.
</p>

<!-- O bien cambia el src de una imagen por el binding [src]. -->
<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>

Cuando se pulsa el botón:

  1. El estado se actualiza con currentAnimal, que se ha definido como 'cat'.
  2. Se evalúan las expresiones que dependen de currentAnimal:

    • 'This is a ' + currentAnimal + '.' => 'This is a cat.'
    • myAnimals[currentAnimal].style => 'redBackground'
    • myAnimals[currentAnimal].imageUrl => /img/cat.jpg
  3. Se actualizan los bindings que dependen de las expresiones modificadas:

    • El texto del primer elemento <p> será "This is a cat".
    • El atributo class del segundo elemento <p> será" "redBackground".
    • El elemento amp-img hará que se muestre la imagen de un gato.

Prueba la demostración de este ejemplo con anotaciones de código.

Información detallada

País

Cada documento AMP que utiliza amp-bind contiene datos JSON mutables que afectan a dicho documento, a los que llamamos estado.

Inicializar el estado mediante amp-state

El estado de amp-bind se puede inicializar mediante el componente amp-state:

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

Las expresiones pueden hacer referencia a variables de estado mediante la sintaxis de puntos. En este ejemplo, myState.foo dará como resultado "bar".

  • El JSON secundario de un elemento <amp-state> puede tener un tamaño máximo de 100 KB.
  • También se puede especificar una URL de CORS para un elemento <amp-state> en lugar de una secuencia de comandos JSON secundaria. Para obtener más información, consulta el Anexo.

Actualizar el estado

La acción refresh es compatible con este componente y se puede utilizar para actualizar el contenido del estado.

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

Actualizar el estado mediante AMP.setState()

La acción AMP.setState() combina una literal de objeto con el estado. Por ejemplo, cuando se pulsa el botón que aparece más abajo, AMP.setState() combinará mediante deepmerge la literal de objeto con el estado.

<!-- 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 general, los objetos anidados se combinarán con hasta 10 objetos por debajo. Se pueden omitir todas las variables, incluidas las que introduce amp-state.

Cuando se activa debido a determinados eventos, AMP.setState() también puede acceder a datos relacionados con los eventos de la propiedad 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})">

Modificar el historial mediante AMP.pushState()

La acción AMP.pushState() es similar a AMP.setState(), con la diferencia de que también añade una entrada a la pila del historial de navegación. Al deshacer esta entrada del historial (por ejemplo, volviendo a la página anterior), se restaura el valor anterior de las variables que define AMP.pushState().

Por ejemplo:

<button on="tap:AMP.pushState({foo: '123'})">Set 'foo' to 123</button>
  • Al tocar el botón, se define la variable foo en 123 y se envía una nueva entrada al historial.
  • Al volver a la página anterior, se restaurará el valor previo de foo, es decir, "bar" (equivale a hacer una llamada a AMP.setState({foo: 'bar'}).

Expresiones

Las expresiones son similares a JavaScript, con algunas diferencias importantes.

Diferencias con respecto a JavaScript

  • Las expresiones solo pueden acceder al estado del documento al que pertenecen.
  • Las expresiones ****no tienen acceso a variables globales como window o document.
  • Solo se pueden utilizar los operadores y las funciones incluidos en la lista blanca.
  • Por lo general, no se admiten las funciones, las clases ni los bucles personalizados. Se admiten las funciones de flecha como parámetros; por ejemplo, Array.prototype.map.
  • Las variables no definidas y los índices de matriz fuera de límites devuelven null en lugar de undefined o de generar errores.
  • Actualmente, una expresión puede tener un máximo de 50 operandos por cuestiones de rendimiento. Ponte en contacto con nosotros si esta cantidad no te resulta suficiente.

Encontrarás la expresión gramatical completa y la implementación en bind-expr-impl.jison y bind-expression.js.

Ejemplos

Las expresiones que aparecen a continuación son válidas:

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

Funciones incluidas en la lista blanca

Tipo de objeto Funciones Ejemplo
Matriz1 concat
filter
includes
indexOf
join
lastIndexOf
map
reduce
slice
some
sort (no es in-place)
splice (no es 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)
Número toExponential
toFixed
toPrecision
toString
// Returns 3.
                (3.14).toFixed()
// Returns '3.14'.
                  (3.14).toString()
Cadena charAt
charCodeAt
concat
indexOf
lastIndexOf
slice
split
substr
substring
toLowerCase
toUpperCase
// Returns 'abcdef'.
                      abc'.concat('def')
Operación matemática2 abs
ceil
floor
max
min
random
round
sign
// Returns 1.
                          abs(-1)
Objeto2 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')

1 Las funciones de flecha de un solo parámetro no pueden tener paréntesis. Por ejemplo, utiliza x => x + 1 en lugar de (x) => x + 1. Además, sort() y splice() devuelven copias modificadas en lugar de funcionar in situ. 2 Las funciones estáticas no llevan espacios de nombre. Por ejemplo, utiliza abs(-1) en lugar de Math.abs(-1).

Definir macros mediante amp-bind-macro

Los fragmentos de expresión de amp-bind se pueden reutilizar definiendo un amp-bind-macro. Este elemento` permite definir una expresión que utiliza cero o más argumentos y hace referencia al estado actual. Se puede invocar una macro como si fuera una función haciendo referencia en cualquier parte del documento al valor de su atributoid`.

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

<div>
  El círculo tiene un área de <span [text]="circleArea(myCircle.radius)">0</span>.
</div>

Una macro también puede llamar a otras macros que se han definido antes que a sí misma. Una macro no puede hacerse llamadas a sí misma de forma recursiva.

Bindings

Un binding es un atributo especial del formulario [property] que vincula la propiedad de un elemento con una expresión. También se puede utilizar una sintaxis alternativa compatible con XML mediante data-amp-bind-property.

Cuando el estado cambia, las expresiones se vuelven a evaluar y las propiedades de los elementos vinculados se actualizan con los resultados de la nueva expresión.

amp-bind admite data bindings para cuatro tipos de estado de elemento:

Tipo Atributos Información detallada
Node.textContent [text] Compatible con la mayoría de los elementos de texto.
Clases de CSS [class] El resultado de la expresión debe ser una cadena delimitada por espacios.
Atributo hidden [hidden] Debe ser una expresión booleana.
Tamaño de los elementos AMP [width]
[height]
Cambia la anchura o la altura del elemento AMP.
Atributos específicos de elementos Varios

Notas sobre los bindings:

  • Por motivos de seguridad, no se permite hacer bindings con innerHTML.
  • Todos los bindings de atributo se depuran para eliminar los valores que no son seguros (p. ej., javascript:).
  • Los resultados de las expresiones booleanas habilitan o inhabilitan los atributos booleanos. Por ejemplo: <amp-video [controls]="expr"...>. Cuando expr da como resultado true, el elemento <amp-video> tiene el atributo controls. Cuando expr da como resultado false, se elimina el atributo controls.
  • Incluir caracteres de corchetes [ y ] en nombres de atributos puede dar problemas al escribir XML (p. ej., XHTML o JSX) o atributos a través de las API de DOM. En estos casos, utiliza la sintaxis alternativa data-amp-bind-x="foo" en lugar de [x]="foo".

Atributos específicos de los elementos

Solo se admiten los bindings a los siguientes componentes y atributos:

Componente Atributos Comportamiento
<amp-brightcove> [data-account]
[data-embed]
[data-player]
[data-player-id]
[data-playlist-id]
[data-video-id]
Cambia el vídeo de Brightcove que se muestra.
<amp-carousel type=slides> [slide]* Cambia el índice de diapositiva que se muestra actualmente. Ver un ejemplo
<amp-date-picker> [min]
[max]
Define la fecha más temprana que se puede seleccionar.
Define la fecha más tardía que se puede seleccionar.
<amp-google-document-embed> [src]
[title]
Muestra el documento en la URL actualizada.
Cambia el título del documento.
<amp-iframe> [src] Cambia la URL de origen del iframe.
<amp-img> [alt]
[attribution]
[src]
[srcset]
Al hacer un binding a [src], asegúrate de hacerlo también a [srcset] para que el funcione en caché.
Consulta los atributos de "amp-img" correspondientes.
<amp-lightbox> [open]* Muestra u oculta el lightbox. Consejo: Utiliza on="lightboxClose: AMP.setState(...)" para actualizar las variables cuando el lightbox esté cerrado.
<amp-list> [src] Si la expresión es una cadena, recupera y renderiza un JSON de la URL de la cadena; si es un objeto o una matriz, renderiza los datos de la expresión.
<amp-selector> [selected]*
[disabled]
Cambia los elementos secundarios seleccionados actualmente
identificados por sus valores de atributo option. Admite una lista de valores separados por comas si hay varios elementos seleccionados. Ver un ejemplo
<amp-state> [src] Recupera un JSON de la nueva URL y lo combina con el estado que ya existe. Ten en cuenta que la siguiente actualización ignorará los elementos <amp-state> para evitar los ciclos.
<amp-video> [alt]
[attribution]
[controls]
[loop]
[poster]
[preload]
[src]
Consulta los atributos de "amp-video" correspondientes.
<amp-youtube> [data-videoid] Cambia el vídeo de YouTube que se muestra.