AMP

amp-bind

Menambahkan interaktivitas kustom dengan data binding dan ekspresi.

Skrip yang Diperlukan
<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
Contoh
Tutorial Membuat halaman AMP yang interaktif

Ringkasan

Komponen amp-bind memungkinkan Anda untuk menambahkan interaktivitas stateful kustom ke halaman AMP melalui data binding dan ekspresi yang mirip JS.

Tonton video ini untuk mengenal amp-bind.

Contoh sederhana

Pada contoh berikut, menge-tap tombol akan mengubah teks elemen <p> dari "Hello World" menjadi "Hello amp-bind".

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

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

Untuk menjaga performa dan menghindari risiko loncatan konten, amp-bind tidak mengevaluasi ekspresi saat halaman dimuat. Ini berarti elemen visual harus diberi status default dan tidak mengandalkan amp-bind untuk render awal.

Bagaimana cara kerjanya?

amp-bind memiliki tiga komponen utama:

  1. Status: Status JSON lingkup dokumen yang dapat berubah. Pada contoh di atas, status masih kosong sebelum tombol di-tap. Setelah tombol di-tap, statusnya menjadi {foo: 'amp-bind'}.
  2. Ekspresi: Merupakan ekspresi mirip JavaScript yang dapat merujuk ke state. Contoh di atas memiliki ekspresi tunggal, 'Hello ' + foo, yang menggabungkan literal string 'Hello 'dan variabel status foo. Ada batas 100 operand yang dapat digunakan dalam sebuah ekspresi.
  3. Binding: Merupakan atribut khusus dari bentuk [properti] yang menautkan properti elemen ke sebuah expression. Contoh di atas memiliki binding tunggal, [text], yang akan mengubah <p> teks elemen setiap kali nilai ekspresi berubah.

amp-bind memerlukan penanganan khusus untuk memastikan kecepatan, keamanan, dan performa di halaman AMP.

Contoh yang sedikit lebih rumit

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

Ketika tombol ditekan:

  1. Status diubah dengan currentAnimal yang ditetapkan ke 'cat'.
  2. Ekspresi yang bergantung pada currentAnimal dievaluasi:

    • 'This is a ' + currentAnimal + '.' => 'This is a cat.'
    • myAnimals[currentAnimal].style => 'redBackground'
    • myAnimals[currentAnimal].imageUrl => /img/cat.jpg
  3. Binding yang bergantung pada ekspresi yang telah diubah akan diubah:

    • Teks elemen <p> pertama akan berbunyi "This is a cat.".
    • Atribut class elemen <p> kedua akan menjadi "redBackground".
    • Elemen amp-img akan menampilkan gambar seekor kucing.

Cobalah demo langsung untuk contoh ini dengan anotasi kode.

Detail

Status

Setiap dokumen AMP yang menggunakan amp-bind memiliki data JSON lingkup dokumen yang dapat diubah, atau status.

Menginisialisasi status dengan amp-state

Status amp-bind dapat diinisialisasi dengan komponen amp-state:

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

Ekspresi dapat merujuk variabel status melalui sintaks titik. Dalam contoh ini, myState.foo akan mengevaluasi "bar".

  • JSON turunan elemen <amp-state> memiliki ukuran maksimal 100 KB.
  • Elemen <amp-state> juga dapat menentukan URL CORS, bukan skrip JSON turunan. Lihat Apendiks untuk mengetahui detailnya.

Me-refresh status

Tindakan refresh didukung oleh komponen ini dan dapat digunakan untuk me-refresh konten status.

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

Mengubah status dengan AMP.setState()

Tindakan AMP.setState() menggabungkan literal objek ke dalam status. Misalnya, saat tombol di bawah ditekan, AMP.setState() akan menggabungkan secara mendalam literal objek dengan status.

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

Secara umum, objek bertingkat akan digabungkan hingga kedalaman maksimal 10. Semua variabel, termasuk yang diperkenalkan oleh amp-state, dapat diganti.

Jika dipicu oleh peristiwa tertentu, AMP.setState() juga dapat mengakses data terkait peristiwa di properti 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})">

Mengubah histori dengan AMP.pushState()

Tindakan AMP.pushState() mirip dengan AMP.setState() kecuali tindakan ini juga mendorong entri baru ke tumpukan histori browser. Memunculkan entri histori ini (misalnya dengan menavigasi mundur) akan memulihkan nilai variabel sebelumnya yang ditetapkan oleh AMP.pushState().

Misalnya:

<button on="tap:AMP.pushState({foo: '123'})">Set 'foo' to 123</button>
  • Menge-tap tombol tersebut akan menetapkan variabel foo ke 123 dan mengirimkan entri histori baru.
  • Menavigasi mundur akan memulihkan foo ke nilai sebelumnya, "bar" (setara dengan memanggil AMP.setState({foo: 'bar'}).

Ekspresi

Ekspresi mirip dengan JavaScript dengan beberapa perbedaan penting.

Perbedaan dengan JavaScript

  • Ekspresi hanya dapat mengakses status dokumen penampungnya.
  • Ekspresi tidak memiliki akses ke elemen global seperti window atau document.
  • Hanya operator dan fungsi yang diizinkan yang dapat digunakan.
  • Fungsi, class, dan loop kustom secara umum tidak diizinkan. Fungsi panah diizinkan sebagai parameter, misalnya Array.prototype.map.
  • Indeks array melebihi batas dan variabel yang tidak ditentukan akan menampilkan null, bukan undefined atau memunculkan error.
  • Ekspresi tunggal saat ini dibatasi 50 operand untuk menjaga performa. Harap hubungi kami jika alokasi ini tidak memadai untuk kasus penggunaan Anda.

Implementasi dan tata bahasa lengkap ekspresi dapat dilihat di bind-expr-impl.jison dan bind-expression.js.

Contoh

Berikut adalah semua ekspresi yang valid:

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

Fungsi yang diizinkan

Jenis objek Fungsi Contoh
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')

1Fungsi panah parameter tunggal tidak dapat menggunakan tanda kurung, misalnya gunakan x => x + 1 bukan (x) => x + 1. Selain itu, sort() dan splice() akan menampilkan salinan termodifikasi, bukan mengoperasikan in-place. 2Fungsi statis tidak di-namespace, misalnya gunakan abs(-1), bukan Math.abs(-1).

Menentukan makro dengan amp-bind-macro

Fragmen ekspresi amp-bind dapat digunakan kembali dengan menentukan amp-bind-macro. Elemen amp-bind-macro memungkinkan Anda menentukan ekspresi yang memerlukan nol atau lebih argumen dan merujuk ke status saat ini. Makro dapat dipanggil seperti fungsi dengan merujuk nilai atribut id-nya dari mana saja dalam dokumen Anda.

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

Makro juga dapat memanggil makro lain yang ditentukan sebelum makro itu sendiri. Makro tidak dapat memanggil dirinya sendiri secara berulang.

Binding

Binding adalah atribut khusus dari bentuk [property] yang menautkan properti sebuah elemen ke sebuah ekspresi. Sintaks alternatif yang kompatibel dengan XML juga dapat digunakan dalam bentuk data-amp-bind-property.

Ketika status berubah, ekspresi dievaluasi ulang dan properti elemen terikat akan diubah dengan hasil ekspresi baru.

amp-bind mendukung data binding di empat jenis status elemen:

Jenis Atribut Detail
Node.textContent [text] Didukung pada sebagian besar elemen teks.
Class CSS [class] Hasil ekspresi harus berupa string yang dipisahkan spasi.
Atribut hidden [hidden] Harus berupa ekspresi boolean.
Ukuran elemen AMP [width]
[height]
Mengubah lebar dan/atau tinggi elemen AMP.
Atribut khusus elemen Bervariasi

Catatan tentang binding:

  • Demi keamanan, binding ke innerHTML tidak diizinkan.
  • Semua binding atribut dibersihkan dari nilai yang tidak aman (misalnya javascript:).
  • Hasil ekspresi boolean mengalihkan atribut boolean. Misalnya: <amp-video [controls]="expr"...>. Saat expr dievaluasi ke true, elemen <amp-video> memiliki atribut controls. Saat expr dievaluasi ke false, atribut controls akan dihapus.
  • Karakter tanda kurung [ dan ] dalam nama atribut dapat menyulitkan saat menulis XML (misalnya XHTML, JSX) atau menulis atribut melalui DOM API. Dalam kasus ini, gunakan sintaks alternatif data-amp-bind-x="foo", bukan [x]="foo".

Atribut khusus elemen

Hanya binding ke komponen dan atribut berikut yang diizinkan:

Komponen Atribut Perilaku
<amp-brightcove> [data-account]
[data-embed]
[data-player]
[data-player-id]
[data-playlist-id]
[data-video-id]
Mengubah video Brightcove yang ditampilkan.
<amp-carousel type=slides> [slide]* Mengubah indeks slide yang sedang ditampilkan. Lihat contoh.
<amp-date-picker> [min]
[max]
Menetapkan tanggal paling awal yang dapat dipilih
Menetapkan tanggal paling akhir yang dapat dipilih
<amp-google-document-embed> [src]
[title]
Menampilkan dokumen pada URL yang diubah.
Mengubah judul dokumen.
<amp-iframe> [src] Mengubah URL sumber iframe.
<amp-img> [alt]
[attribution]
[src]
[srcset]
Saat melakukan binding ke [src], pastikan Anda juga melakukannya ke [srcset] agar binding berfungsi pada cache.
Lihat atribut amp-img yang terkait.
<amp-lightbox> [open]* Mengaktifkan tampilan lightbox. Tips: Gunakan on="lightboxClose: AMP.setState(...)" untuk mengubah variabel ketika lightbox ditutup.
<amp-list> [src] Jika ekspresi berupa string, mengambil dan merender JSON dari URL string. Jika ekspresi berupa objek atau array, merender data ekspresi.
<amp-selector> [selected]*
[disabled]
Mengubah elemen turunan terpilih saat ini
yang diidentifikasi oleh nilai atribut option-nya. Mendukung daftar dipisahkan koma yang memuat nilai untuk beberapa pilihan. Lihat contoh.
<amp-state> [src] Mengambil JSON dari URL baru dan menggabungkannya ke dalam status yang ada. Perhatikan bahwa perubahan berikut akan mengabaikan elemen <amp-state> untuk mencegah siklus.
<amp-video> [alt]
[attribution]
[controls]
[loop]
[poster]
[preload]
[src]
Melihat atribut amp-video yang terkait.
<amp-youtube> [data-videoid] Mengubah video YouTube yang ditampilkan.
<a> [href] Mengubah link.
<button> [disabled]
[type]
[value]
Melihat atribut tombol yang terkait.
<details> [open] Melihat atribut detail yang terkait.
<fieldset> [disabled] Mengaktifkan atau menonaktifkan fieldset.
<image> [xlink:href]
Melihat atribut gambar yang terkait.
<input> [accept]
[accessKey]
[autocomplete]
[checked]
[disabled]
[height]
[inputmode]
[max]
[maxlength]
[min]
[minlength]
[multiple]
[pattern]
[placeholder]
[readonly]
[required]
[selectiondirection]
[size]
[spellcheck]
[step]
[type]
[value]
[width]
Melihat atribut input yang terkait.
<option> [disabled]
[label]
[selected]
[value]
Melihat atribut opsi yang terkait.
<optgroup> [disabled]
[label]
Melihat atribut optgroup yang terkait
<select> [autofocus]
[disabled]
[multiple]
[required]
[size]
Melihat atribut pilih yang terkait.
<source> [src]
[type]
Melihat atribut sumber yang terkait.
<track> [label]
[src]
[srclang]
Melihat atribut track yang terkait.
<textarea> [autocomplete]
[autofocus]
[cols]
[disabled]
[maxlength]
[minlength]
[placeholder]
[readonly]
[required]
[rows]
[selectiondirection]
[selectionend]
[selectionstart]
[spellcheck]
[wrap]
Melihat atribut textarea yang terkait.

*Menunjukkan atribut yang dapat diikat yang tidak memiliki pasangan yang tidak dapat diikat.

Debugging

Jalankan pengujian dalam mode pengembangan (dengan fragmen URL #development=1) untuk menandai peringatan dan error selama pengembangan dan untuk mengakses fungsi debug khusus.

Peringatan

Dalam mode pengembangan, amp-bind akan mengeluarkan peringatan saat nilai default atribut terikat tidak cocok dengan hasil awal ekspresi yang terkait. Hal ini dapat membantu mencegah mutasi tak terduga yang disebabkan oleh perubahan pada variabel status lainnya. Contoh:

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

Dalam mode pengembangan, amp-bind juga akan mengeluarkan peringatan saat menghilangkan referensi ke properti atau variabel yang tidak ditentukan. Hal ini juga dapat membantu mencegah mutasi tak terduga akibat hasil ekspresi null. Contoh:

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

Error

Ada beberapa jenis error runtime yang mungkin ditemui ketika bekerja dengan amp-bind.

Jenis Pesan Saran
Binding tidak valid Binding to [someBogusAttribute] on <P> is not allowed. Gunakan hanya binding yang disetujui.
Error sintaks Expression compilation error in... Verifikasi ekspresi dari kesalahan ketik.
Fungsi tidak diizinkan alert is not a supported function. Gunakan hanya fungsi yang diizinkan.
Hasil yang dibersihkan "javascript:alert(1)" is not a valid result for [href]. Hindari protokol URL atau ekspresi dilarang yang akan menggagalkan Validator AMP.
Pelanggaran CSP Refused to create a worker from 'blob:...' because it violates the following Content Security Policy directive... Tambahkan default-src blob: ke Kebijakan Keamanan Konten asal. amp-bind mendelegasikan pekerjaan penting ke Pekerja Web khusus untuk memastikan performa yang baik.

Men-debug Status

Gunakan AMP.printState() untuk mencetak status saat ini ke konsol.

Lampiran

Spesifikasi <amp-state>

Elemen amp-state dapat berisi elemen <script> turunan ATAU atribut src yang berisi URL CORS ke endpoint JSON jarak jauh, tetapi tidak keduanya.

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

Pengelompokan XHR

AMP mengelompokkan XMLHttpRequest (XHR) ke endpoint JSON, artinya, Anda dapat menggunakan satu permintaan data JSON sebagai sumber data untuk banyak konsumen (misalnya beberapa elemen <amp-list>) di sebuah halaman AMP. Sebagai contoh, jika elemen amp-list membuat XHR ke sebuah endpoint, sementara XHR sedang dalam periode tayang, semua XHR berikutnya ke endpoint yang sama tidak akan terpicu dan sebaliknya akan menampilkan hasil dari XHR pertama.

Atribut

src URL endpoint jarak jauh yang akan menampilkan JSON yang akan mengubah amp-state. Harus berupa layanan HTTP CORS. Atribut src memungkinkan semua substitusi variabel URL standar. Lihat Panduan Substitusi untuk informasi selengkapnya.
Endpoint harus mengimplementasikan persyaratan yang ditentukan dalam spesifikasi permintaan CORS di AMP.
credentials (opsional) Menentukan opsi credentials seperti yang ditentukan oleh Fetch API.
  • Nilai yang didukung: `omit`, `include`
  • Default: `omit`
Untuk mengirim kredensial, teruskan nilai include. Jika nilai ini ditetapkan, respons harus mengikuti panduan keamanan CORS AMP.

Penggabungan mendalam dengan AMP.setState()

Ketika AMP.setState() dipanggil, amp-bind akan menggabungkan secara mendalam literal objek yang disediakan dengan status saat ini. Semua variabel dari literal objek akan ditulis ke status secara langsung kecuali untuk objek bertingkat, yang akan digabung secara berulang. Primitive dan array dalam status akan selalu ditimpa oleh variabel dengan nama yang sama dalam literal objek.

Perhatikan contoh berikut:

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

Saat tombol pertama ditekan, status akan berubah menjadi:

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

Saat tombol kedua ditekan, amp-bind secara berulang akan menggabungkan argumen literal objek, {employee: {age: 64}}, ke dalam status yang ada.

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

employee.age telah diubah, tetapi kunci employee.name dan employee.vehicle tidak berubah.

Perhatikan bahwa amp-bind akan memunculkan error jika Anda memanggil AMP.setState() dengan literal objek yang berisi referensi melingkar.

Menghapus variabel

Hapus variabel status yang ada dengan menetapkan nilainya ke null di AMP.setState(). Dimulai dengan status dari contoh sebelumnya, menekan:

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

akan mengubah status menjadi:

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

Demikian juga menekan:

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

akan mengubah status menjadi:

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

Tata bahasa ekspresi

Tata bahasa mirip BNF untuk ekspresi 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
Perlu bantuan lainnya?

Anda telah membaca dokumen ini belasan kali, tetapi belum semua pertanyaan Anda terjawab? Mungkin orang lain merasakan hal yang sama. Berinteraksilah dengan mereka di Stack Overflow.

Kunjungi Stack Overflow
Menemukan bug atau ada fitur yang kurang?

Proyek AMP sangat menganjurkan partisipasi dan kontribusi Anda! Kami berharap Anda akan terus ambil bagian dalam komunitas sumber terbuka kami, tetapi kami juga menerima kontribusi satu kali untuk topik tertentu yang Anda minati.

Kunjungi GitHub