AMP

amp-bind

Description

Permite que os elementos se alterem em resposta às ações do usuário ou a mudanças nos dados por meio de expressões simples semelhantes às do JavaScript e vinculação de dados.

 

Required Scripts

<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>

Adiciona interatividade personalizada com expressões e vinculação de dados.

Script obrigatório
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
Exemplos
Tutoriais Criação de páginas AMP interativas

Visão geral

O componente amp-bind permite que você adicione interatividade personalizada com estado às suas páginas AMP por meio de vinculação de dados e expressões semelhantes às do JavaScript.

Assista a este vídeo de introdução ao amp-bind.

Um exemplo simples

No exemplo a seguir, o toque no botão altera o texto do elemento <p> de “Hello World” para “Hello amp-bind”.

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

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

para melhorar o desempenho e evitar o risco de saltos de conteúdo inesperados, o amp-bind não avalia expressões durante o carregamento da página. Isso significa que os elementos visuais precisam receber um estado padrão e não depender de amp-bind para a renderização inicial.

Como funciona?

amp-bind tem três componentes principais:

  1. Estado: um estado JSON mutável com escopo de documento. No exemplo acima, o estado está vazio antes do toque no botão. Depois de tocar no botão, o estado é {foo: 'amp-bind'}.
  2. Expressões: são expressões semelhantes às do JavaScript que podem fazer referência ao estado. O exemplo acima tem uma única expressão, Hello ' + foo, que concatena a string literal Hello e a variável de estado foo. Há um limite de 100 operandos que podem ser usados em uma expressão.
  3. Vinculações: são atributos especiais da forma [property] que vinculam a propriedade de um elemento a uma expressão. O exemplo acima tem uma única vinculação, [text], que atualiza o texto do elemento <p> toda vez que o valor da expressão é alterado.

O amp-bind tem um cuidado especial para garantir velocidade, segurança e desempenho para as páginas AMP.

Um exemplo um pouco mais complexo

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

<button on="tap:AMP.setState({currentAnimal: 'cat'})">Set to Cat</button>

Quando o botão é pressionado:

  1. O estado é atualizado com currentAnimal definido como 'cat'.
  2. As expressões que dependem de currentAnimal são avaliadas:

    • 'This is a ' + currentAnimal + '.' => 'This is a cat.'
    • myAnimals[currentAnimal].style => 'redBackground'
    • myAnimals[currentAnimal].imageUrl => /img/cat.jpg
  3. As vinculações que dependem das expressões alteradas são atualizadas:

    • O texto do primeiro elemento <p> será "This is a cat".
    • O atributo class do segundo elemento <p> será "redBackground".
    • O elemento amp-img mostrará a imagem de um gato.

teste a demonstração ao vivo desse exemplo com anotações de código.

Detalhes

Estado

Cada documento AMP que usa o amp-bind tem dados JSON mutáveis com escopo de documento, ou estado.

Inicializar o estado com amp-state

O estado do amp-bind pode ser inicializado com o componente amp-state:

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

As expressões podem referenciar variáveis de estado com a sintaxe de dot. Neste exemplo, myState.foo será avaliado como "bar".

  • O JSON filho de um elemento <amp-state> tem o tamanho máximo de 100 KB.
  • Um elemento <amp-state> também pode especificar um URL CORS em vez de um script JSON filho. Consulte o Apêndice para ver mais detalhes.

Estado de atualização

A ação refresh é compatível com este componente e pode ser usada para atualizar o conteúdo do 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>

Atualizar o estado com AMP.setState()

A ação AMP.setState() mescla o literal de um objeto ao estado. Por exemplo, quando o botão abaixo for pressionado, o AMP.setState() mesclará o literal do objeto com o 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>

Em geral, os objetos aninhados são mesclados com uma profundidade máxima de 10. Todas as variáveis, incluindo as introduzidas pelo amp-state, podem ser modificadas.

Quando acionado por determinados eventos, o AMP.setState() também pode acessar dados relacionados a eventos na propriedade 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 o histórico com AMP.pushState()

A ação AMP.pushState() é semelhante à AMP.setState(), mas também envia uma nova entrada para a pilha do histórico do navegador. Abrir essa entrada do histórico (por exemplo, navegando de volta) restaura o valor anterior de variáveis definidas por AMP.pushState().

Por exemplo:

<button on="tap:AMP.pushState({foo: '123'})">Set 'foo' to 123</button>
  • Tocar no botão configura a variável foo como 123 e envia uma nova entrada de histórico.
  • Navegar de volta restaura foo para o valor anterior, "bar" (o que é equivalente a chamar AMP.setState({foo: 'bar'}).

Expressões

As expressões são semelhantes às do JavaScript, mas têm algumas diferenças importantes.

Diferenças em relação ao JavaScript

  • As expressões só podem acessar o estado do documento que as contém.
  • As expressões não têm acesso a globais, como window ou document.
  • Apenas operadores e funções da lista de permissões podem ser usados.
  • Funções, classes e loops personalizados geralmente não são permitidos. As funções de seta são permitidas como parâmetros, por exemplo, Array.prototype.map.
  • Variáveis indefinidas e array-index-out-of-bounds retornam null, em vez de undefined ou de gerar erros.
  • Uma expressão única atualmente está limitada a 50 operandos, por motivos de desempenho. Fale conosco se esse número for insuficiente para seu caso de uso.

A gramática e a implementação completas da expressão podem ser encontradas em bind-expr-impl.jison e bind-expression.js.

Exemplos

Todas as expressões a seguir são válidas:

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

Funções da lista de permissões

Tipo de objeto Funções Exemplo
Array1 concat
filter
includes
indexOf
join
lastIndexOf
map
reduce
slice
some
sort (não em vigor)
splice (não em vigor)
// 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')

1As funções de seta com um único parâmetro não podem ter parênteses. Por exemplo, use x => x + 1, em vez de (x) => x + 1. Além disso, sort() e splice() retornam cópias modificadas em vez de operar no local.

2Funções estáticas não contêm namespaces. Por exemplo, use abs(-1) em vez de Math.abs(-1).

Definir macros com amp-bind-macro

Fragmentos da expressão amp-bind podem ser reutilizados definindo uma amp-bind-macro. O elemento amp-bind-macro permite que você defina uma expressão que use zero ou mais argumentos e faça referência ao estado atual. Uma macro pode ser invocada da mesma forma que uma função, referenciando o valor do atributo id em qualquer lugar no seu documento.

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

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

Uma macro também pode chamar outras macros definidas antes dela mesma. Uma macro não pode chamar a si mesma recorrentemente.

Vinculações

Uma vinculação é um atributo especial da forma [property] que vincula a propriedade de um elemento a uma expressão. Como alternativa, uma sintaxe compatível com XML também pode ser usada na forma de data-amp-bind-property.

Quando o estado é alterado, as expressões são reavaliadas e as propriedades dos elementos vinculados são atualizadas com os resultados da nova expressão.

amp-bind é compatível com vinculações de dados em quatro tipos de estados de elementos:

Tipo Atributos Detalhes
Node.textContent [text] Compatível com a maioria dos elementos de texto.
Classes CSS [class] O resultado da expressão precisa ser uma string delimitada por espaços.
Atributo hidden [hidden] Precisa ser uma expressão booleana.
Tamanho dos elementos AMP [width]
[height]
Altera a largura e/ou altura do elemento AMP.
Atributos específicos de elementos Vários

Observações sobre vinculações:

  • Por motivos de segurança, a vinculação a innerHTML não é permitida.
  • Todas as vinculações de atributo são verificadas em busca de valores não seguros (por exemplo, javascript:).
  • Resultados de expressão booleana alternam atributos booleanos. Por exemplo: <amp-video [controls]="expr"...>. Quando expr é avaliado como true, o elemento <amp-video> tem o atributo controls. Quando expr é avaliado como false, o atributo controls é removido.
  • Os caracteres de colchete [ e ] em nomes de atributos podem ser problemáticos quando se escreve em XML (por exemplo, XHTML, JSX) ou ao escrever atributos por meio de APIs DOM. Nesses casos, use a sintaxe alternativa data-amp-bind-x="foo", em vez de [x]="foo".

Atributos específicos de elementos

Apenas a vinculação aos seguintes componentes e atributos é permitida:

Componente Atributos Comportamento
<amp-brightcove> [data-account]
[data-embed]
[data-player]
[data-player-id]
[data-playlist-id]
[data-video-id]
Altera o vídeo Brightcove exibido.
<amp-carousel type=slides> [slide]* Altera o índice do slide exibido no momento. Veja um exemplo.
<amp-date-picker> [min]
[max]
Define a data selecionável mais antiga.
Define a data selecionável mais recente.
<amp-google-document-embed> [src]
[title]
Exibe o documento no URL atualizado.
Altera o título do documento.
<amp-iframe> [src] Altera o URL de origem do iframe.
<amp-img> [alt]
[attribution]
[src]
[srcset]
Ao vincular a [src], vincule também a [srcset] para que a vinculação funcione no cache.
Veja os atributos amp-img correspondentes.
<amp-lightbox> [open]* Alterna a exibição do lightbox. Dica: use on="lightboxClose: AMP.setState(...)" para atualizar variáveis quando o lightbox estiver fechado.
<amp-list> [src] Se a expressão for uma string, o atributo buscará e renderizará JSON a partir do URL da string. Se a expressão for um objeto ou matriz, o atributo renderizará os dados da expressão.
<amp-selector> [selected]*
[disabled]
Altera os elementos filhos selecionados atualmente
identificados pelos valores do atributo option. Aceita uma lista separada por vírgulas de valores para seleção múltipla. Veja um exemplo.
<amp-state> [src] Busca JSON a partir do novo URL e mescla-o com o estado existente. Observe que a atualização seguinte ignorará os elementos <amp-state> para evitar ciclos.
<amp-video> [alt]
[attribution]
[controls]
[loop]
[poster]
[preload]
[src]
Veja os atributos amp-video correspondentes.
<amp-youtube> [data-videoid] Altera o vídeo do YouTube exibido.
<a> [href] Altera o link.
<button> [disabled]
[type]
[value]
Veja os atributos de button correspondentes.
<details> [open] Veja os atributos de details correspondentes.
<fieldset> [disabled] Ativa ou desativa o conjunto de campos.
<image> [xlink:href]
Veja os atributos de image correspondentes.
<input> [accept]
[accessKey]
[autocomplete]
[checked]
[disabled]
[height]
[inputmode]
[max]
[maxlength]
[min]
[minlength]
[multiple]
[pattern]
[placeholder]
[readonly]
[required]
[selectiondirection]
[size]
[spellcheck]
[step]
[type]
[value]
[width]
Veja os atributos de input correspondentes.
<option> [disabled]
[label]
[selected]
[value]
Veja os atributos de option correspondentes.
<optgroup> [disabled]
[label]
Veja os atributos de optgroup correspondentes.
<select> [autofocus]
[disabled]
[multiple]
[required]
[size]
Veja os atributos de select correspondentes.
<source> [src]
[type]
Veja os atributos de source correspondentes.
<track> [label]
[src]
[srclang]
Veja os atributos de track correspondentes.
<textarea> [autocomplete]
[autofocus]
[cols]
[disabled]
[maxlength]
[minlength]
[placeholder]
[readonly]
[required]
[rows]
[selectiondirection]
[selectionend]
[selectionstart]
[spellcheck]
[wrap]
Veja os atributos de textarea correspondentes.

*Indica atributos vinculáveis que não têm uma contraparte não vinculável.

Depuração

Teste no modo de desenvolvimento (com o fragmento de URL #development=1) para destacar avisos e erros durante o desenvolvimento e para acessar funções especiais de depuração.

Avisos

No modo de desenvolvimento, o amp-bind emite um aviso quando o valor padrão de um atributo vinculado não corresponde ao resultado inicial da expressão correspondente. Isso pode ajudar a evitar mutações não intencionais causadas por alterações em outras variáveis de estado. Exemplo:

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

No modo de desenvolvimento, o amp-bind também emite um aviso ao desreferenciar variáveis ou propriedades indefinidas. Isso também pode ajudar a evitar mutações não intencionais devido a resultados de expressão null. Exemplo:

<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">Some placeholder text.</p>

Erros

Há vários tipos de erros de tempo de execução que podem ser encontrados ao trabalhar com o amp-bind.

Tipo Mensagem Sugestão
Vinculação inválida A vinculação a [someBogusAttribute] em <P> não é permitida. Use somente vinculações da lista de permissões.
Erro de sintaxe Erro de compilação de expressão em… Verifique se há erros de digitação na expressão.
Funções não permitidas alert não é uma função compatível. Use somente funções da lista de permissões.
Resultado corrigido "javascript:alert(1)" não é um resultado válido para [href]. Evite protocolos ou expressões de URL banidos que possam ser reprovados pelo Validador de AMP.
Violação da CSP Criação de um worker a partir de 'blob:...' recusada porque isso viola a seguinte diretiva da Política de Segurança de Conteúdo… Adicione default-src blob: à Política de Segurança de Conteúdo da sua origem. O amp-bind delega o trabalho dispendioso a um worker da Web dedicado para garantir um bom desempenho.

Estado de depuração

Use o AMP.printState() para imprimir o estado atual no console.

Apêndice

Especificação <amp-state>

Um elemento amp-state pode conter um elemento <script> filho OU um atributo src contendo um URL CORS para um endpoint JSON remoto, mas não ambos.

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

<amp-state id="myRemoteState" src="https://data.com/articles.json">
</amp-state>

Criação de lote XHR

O AMP cria lotes XMLHttpRequests (XHRs) em endpoints JSON, ou seja, você pode usar uma única solicitação de dados JSON como uma fonte de dados para vários consumidores (por exemplo, vários elementos <amp-state>) em uma página AMP. Por exemplo, se seu elemento <amp-state> fizer um XHR para um endpoint durante o período de veiculação do XHR, todos os XHRs subsequentes para o mesmo endpoint não serão acionados e, em vez disso, retornarão os resultados do primeiro XHR.

Atributos

src O URL do endpoint remoto que retornará o JSON que atualizará esse amp-state. Ele precisa ser um serviço HTTP CORS. O atributo src permite todas as substituições de variáveis de URL padrão. Consulte o Guia de substituições (em inglês) para ver mais informações.
o endpoint precisa implementar os requisitos definidos nas especificações de Solicitações CORS nas AMP (link em inglês).
credentials (opcional) Define uma opção de credentials conforme especificado pela API Fetch.
  • Valores aceitos: `omit`, `include`
  • Padrão: `omit`
Para enviar credenciais, passe o valor de include. Se esse valor estiver configurado, a resposta precisará seguir as diretrizes de segurança do CORS AMP (link em inglês).

Mesclagem com AMP.setState()

Quando o AMP.setState() é chamado de amp-bind, ele mescla o literal do objeto fornecido com o estado atual. Todas as variáveis do literal do objeto são escritas diretamente no estado, exceto para objetos aninhados, que são mesclados de modo recorrente. Primitivas e matrizes que estão no estado são sempre substituídas por variáveis com o mesmo nome do literal do objeto.

Veja o exemplo a seguir:

{
  <!-- 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 o primeiro botão é pressionado, o estado muda para:

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

Quando o segundo botão for pressionado, o amp-bind mesclará recursivamente o argumento do literal do objeto, {employee: {age: 64}}, com o estado existente.

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

employee.age foi atualizado, mas as chaves employee.name e employee.vehicle não foram alteradas.

O amp-bind gerará um erro se você chamar AMP.setState() com um literal de objeto que contenha referências circulares.

Remover uma variável

Remova uma variável de estado existente definindo o valor dela como null em AMP.setState(). Começando com o estado do exemplo anterior, pressionar:

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

Mudará o estado para:

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

Da mesma forma:

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

Mudará o estado para:

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

Gramática de expressões

A gramática semelhante a BNF para expressões 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
Precisa de mais ajuda?

Você já leu este documento várias vezes, mas ainda ficou com dúvidas sem respostas? Talvez outras pessoas pensem da mesma forma. Procure entrar em contato com elas no Stack Overflow.

Ir para o Stack Overflow
Encontrou um bug ou sente falta de um recurso?

O projeto AMP incentiva fortemente sua participação e contribuições! Esperamos que você se torne um participante assíduo de nossa comunidade de código aberto, mas também agradecemos contribuições pontuais para problemas que você tenha particular interesse.

Ir para o GitHub