- Descripción general
- Un ejemplo muy sencillo
- Información detallada
- País
- Inicializar el estado mediante amp-state
- Actualizar el estado
- Actualizar el estado mediante AMP.setState()
- Modificar el historial mediante AMP.pushState()
- Expresiones
- Diferencias con respecto a JavaScript
- Ejemplos
- Funciones incluidas en la lista blanca
- Definir macros mediante amp-bind-macro
- Bindings
- Atributos específicos de los elementos
- Depuración
- Advertencias
- Errores
- Estado de depuración
- Apéndice
- Especificación de <amp-state>
- Procesamiento por lotes de XHR
- Atributos
- Combinar con deepmerge mediante AMP.setState()
- Eliminar una variable
- Gramática de las expresiones
amp-bind
Description
Permite que los elementos muten como respuesta a las acciones del usuario o a cambios de datos mediante data binding y expresiones simples similares a JS.
Required Scripts
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
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.
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>
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:
- 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'}
. - 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 estadofoo
. Una expresión puede contener un máximo de 100 operandos. - 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:
- El estado se actualiza con
currentAnimal
, que se ha definido como'cat'
. -
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
-
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.
- El texto del primer elemento
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 aAMP.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
odocument
. - 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 deundefined
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 |
---|---|---|
Matriz 1 | 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ática 2 | abs ceil floor max min random round sign | // Returns 1. abs(-1) |
Objeto 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 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 atributo
id`.
<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"...>
. Cuandoexpr
da como resultadotrue
, el elemento<amp-video>
tiene el atributocontrols
. Cuandoexpr
da como resultadofalse
, se elimina el atributocontrols
. - 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 alternativadata-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. |
<a> | [href] | Cambia el enlace. |
<button> | [disabled] [type] [value] | Consulta los atributos de "button" correspondientes. |
<details> | [open] | Consulta los atributos de "details" correspondientes. |
<fieldset> | [disabled] | Habilita o inhabilita el elemento "fieldset". |
<image> | [xlink:href] | Consulta los atributos de "image" correspondientes. |
<input> | [accept] [accessKey] [autocomplete] [checked] [disabled] [height] [inputmode] [max] [maxlength] [min] [minlength] [multiple] [pattern] [placeholder] [readonly] [required] [selectiondirection] [size] [spellcheck] [step] [type] [value] [width] | Consulta los atributos de "input" correspondientes. |
<option> | [disabled] [label] [selected] [value] | Consulta los atributos de "options" correspondientes. |
<optgroup> | [disabled] [label] | Consulta los atributos de "optgroup" correspondientes |
<select> | [autofocus] [disabled] [multiple] [required] [size] | Consulta los atributos de "select" correspondientes. |
<source> | [src] [type] | Consulta los atributos de "source" correspondientes. |
<track> | [label] [src] [srclang] | Consulta los atributos de "track" correspondientes. |
<textarea> | [autocomplete] [autofocus] [cols] [disabled] [maxlength] [minlength] [placeholder] [readonly] [required] [rows] [selectiondirection] [selectionend] [selectionstart] [spellcheck] [wrap] | Consulta los atributos de "textarea" correspondientes. |
* Indica atributos vinculables que no tienen contrapartida que no se pueda vincular.
Depuración
Haz las pruebas en modo de desarrollo (con el fragmento de URL #development=1
) para hacer que se resalten los mensajes de advertencia y error durante el desarrollo y para acceder a funciones de depuración especiales.
Advertencias
En el modo de desarrollo, amp-bind
enviará una advertencia cuando el valor predeterminado de un atributo vinculado no coincida con el resultado inicial de su expresión correspondiente. Esto puede evitar mutaciones no deseadas causadas por cambios en otras variables de estado. Por ejemplo:
<!-- El valor de clase predeterminado del elemento ('def') no coincide con el resultado de la expresión [class] ('abc'), por lo que se emitirá una advertencia en el modo de desarrollo. -->
<p class="def" [class]="'abc'"></p>
En el modo de desarrollo, amp-bind
también enviará una advertencia cuando se eliminen referencias a variables o propiedades no definidas. Esto también puede evitar mutaciones no deseadas debidas a resultados de expresión null
. Por ejemplo:
<amp-state id="myAmpState">
<script type="application/json">
{ "foo": 123 }
</script>
</amp-state></p>
<!-- amp-state#myAmpState no tiene una variable `bar`, por lo que se emitirá una advertencia en el modo de desarrollo. -->
<p [text]="myAmpState.bar">Un texto de marcador de posición.</p>
Errores
Hay varios tipos de errores de tiempo de ejecución que se pueden encontrar al trabajar con amp-bind
.
Tipo | SMS | Sugerencia |
---|---|---|
Binding no válido | No se permite el binding a [someBogusAttribute] en <P>. | Utiliza solo bindings incluidos en la lista blanca. |
Error de sintaxis | Se ha producido un error de compilación de expresiones en... | Comprueba que la expresión no tiene erratas. |
Funciones no incluidas en la lista blanca | La función alert no es compatible. | Utiliza solo funciones incluidas en la lista blanca. |
Resultado depurado | "javascript:alert(1)" no es un resultado válido para [href]. | Evita los protocolos de URL prohibidos o las expresiones que no admita AMP Validator. |
Infracción de la política de seguridad de contenido | No se ha podido crear un worker mediante 'blob:...' porque infringe la siguiente directiva de la política de seguridad de contenido... | Añade default-src blob: a la política de seguridad de contenido de tu origen. amp-bind delega trabajo costoso a un Web Worker dedicado para garantizar un buen rendimiento. |
Estado de depuración
Utiliza AMP.printState()
para imprimir el estado actual en la consola.
Apéndice
Especificación de <amp-state>
Un elemento amp-state
puede contener un elemento secundario <script>
****o bien un atributo src
que contenga una URL CORS de un punto final remoto JSON, pero no ambos.
<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>
Procesamiento por lotes de XHR
AMP envía XMLHttpRequests (XHR) por lotes a puntos de conexión JSON. Es decir, puedes utilizar una sola solicitud de datos JSON como fuente de datos para varios consumidores (p. ej., varios elementos amp-state
) en una página AMP. Por ejemplo, si tu elemento amp-state
hace un XHR a un punto de conexión, y mientras esté procesándose, los XHR posteriores que se hagan al mismo punto de conexión no se activarán, y devolverán en su lugar los resultados del primer XHR.
Atributos
src | URL del punto de conexión remoto que devolverá el JSON que actualizará este amp-state . Debe ser un servicio CORS HTTP. El atributo src admite todas las sustituciones estándar de variables de URL. Para obtener más información, consulta la guía de sustituciones. El punto de conexión debe implementar los requisitos que se detallan en la especificación de las solicitudes CORS de AMP.
|
credentials (opcional) | Define una opción credentials tal y como especifica la API de Fetch.
include . Si se define este valor, la respuesta debe seguir las directrices de seguridad de AMP CORS. |
Combinar con deepmerge mediante AMP.setState()
Cuando se hace una llamada a AMP.setState()
, amp-bind
lleva a cabo una combinación con deepmerge y fusiona la literal del objeto con el estado actual. Todas las variables de la literal del objeto se añaden directamente al estado, excepto los objetos anidados, que se fusionan de forma recursiva. Los primitivos y las matrices que se encuentran en el estado siempre se sobrescriben en la literal del objeto con variables del mismo nombre.
Observa el siguiente ejemplo:
{
<!-- 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>
Cuando se pulsa el primer botón, el estado cambia a:
{
employee: {
name: 'John Smith',
age: 47,
vehicle: 'Car',
}
}
Cuando se pulse el segundo botón, amp-bind
combinará de forma recursiva el argumento de la literal del objeto, {employee: {age: 64}}
, con el estado existente.
{
employee: {
name: 'John Smith',
age: 64,
vehicle: 'Car',
}
}
Se ha actualizado employee.age
, pero las claves employee.name
y employee.vehicle
no han cambiado.
Ten en cuenta que amp-bind
generará un error si haces una llamada a AMP.setState()
utilizando una literal de objeto que contiene referencias circulares.
Eliminar una variable
Puedes eliminar una variable de estado existente definiendo su valor como null
en AMP.setState()
. Empezando por el estado del ejemplo anterior, si se pulsa:
<button on="tap:AMP.setState({employee: {vehicle: null}})"...></button>
El estado cambiará a:
{
employee: {
name: 'John Smith',
age: 48,
}
}
Veamos otro ejemplo parecido:
<button on="tap:AMP.setState({employee: null})"...></button>
Pulsando el botón, el estado cambiará a:
{
<!-- State is empty -->
}
Gramática de las expresiones
Esta es la gramática para las expresiones de amp-bind
, similar a BNF:
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
¿Ha leído este documento una docena de veces pero realmente no responde todas sus preguntas? Quizás otras personas piensen lo mismo: póngase en contacto con ellas en Stack Overflow.
Ir a Stack Overflow ¿Encontró un error o considera que falta una función?¡El proyecto AMP alienta profundamente su participación y contribuciones! Esperamos que se convierta en un miembro permanente de nuestra comunidad de código abierto, pero también agradecemos las contribuciones esporádicas sobre los temas que le apasionan especialmente.
Ir a GitHub