Komponen Dasar

Contoh Dasar

Berikut ini adalah contoh Vue komponen:

// Mendefinisikan komponen baru dengan nama button-counter
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">Anda mengklik saya {{ count }} kali.</button>'
})

Komponen adalah Vue instance yang dapat digunakan kembali dengan nama: pada kasus ini, <button-counter>. Kita bisa menggunakan komponen ini sebagai kustom elemen di dalam instance root Vue yang dibuat dengan new Vue:

<div id="components-demo">
  <button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })

Karena komponen adalah Vue instance yang bisa digunakan kembali, mereka menerima opsi yang sama dengan new Vue, seperti data, computed, watch, methods, dan kait siklus hidup (lifecycle hooks). Satu-satunya pengecualian adalah beberapa opsi khusus seperti el.

Menggunakan Kembali Komponen

Komponen dapat digunakan kembali sebanyak yang Anda inginkan:

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

Perhatikan ketika mengklik tombol, masing-masing mempertahankan count itu sendiri secara terpisah. Itu karena setiap kali Anda menggunakan komponen, instance baru akan dibuat.

data Harus Berupa Fungsi

Ketika kita mendefinisikan komponen <button-counter>, Anda mungkin memperhatikan bahwa data secara tidak langsung berupa sebuah objek, seperti ini:

data: {
  count: 0
}

Sebagai gantinya, opsi data pada komponen harus berupa fungsi, sehingga setiap instance dapat mempertahankan salinan independen dari objek data yang dikembalikan:

data: function () {
  return {
    count: 0
  }
}

Jika Vue tidak memiliki aturan ini, maka ketika mengklik satu tombol akan mempengaruhi semua data, seperti di bawah ini:

Pengorganisasian Komponen

Biasanya aplikasi diorganisasikan ke dalam kumpulan komponen bersarang:

Komponen Bersarang

Sebagai contoh, Anda mungkin memiliki komponen header, bilah samping (sidebar), dan area konten, masing-masing biasanya berisi komponen lain untuk tautan navigasi, posting blog, dan sebagainya.

Untuk menggunakan komponen ini dalam templat, mereka harus didaftarkan agar Vue tahu tentang mereka. Ada dua tipe untuk mendaftarkan: global dan local. Sejauh ini, Kita hanya mendaftarkan komponen secara global, menggunakan Vue.component:

Vue.component('my-component-name', {
  // ... opsi ...
})

Komponen yang terdaftar secara global dapat digunakan dalam templat dari instance Vue Root (new Vue) yang dibuat setelahnya – dan bahkan di dalam semua sub komponen dari pohon komponen Vue instance.

Itu saja yang perlu Anda ketahui tentang pendaftaran untuk saat ini, tetapi setelah selesai membaca halaman ini dan merasa nyaman dengan isinya, kami sarankan untuk kembali lagi nanti untuk membaca panduan lengkap tentang Mendaftarkan Komponen.

Mengoper Data ke Anak Komponen dengan Props

Sebelumnya, kita membuat contoh komponen untuk posting blog. Masalahnya adalah, komponen itu tidak akan berguna kecuali Anda dapat mengoper data ke dalamnya, seperti judul dan konten dari pos tertentu yang ingin kita tampilkan. Di situlah kegunaan props.

Props adalah kustom atribut yang dapat Anda daftarkan pada suatu komponen. Ketika nilai diopen ke atibut prop, itu menjadi properti pada instance komponen itu. Untuk mengoper judul ke komponen posting blog, kita dapat memasukannya dalam daftar properti yang diterima komponen ini, menggunakan opsi props:

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

Sebuah komponen dapat memiliki dapat memiliki banyak props seperti yang Anda inginkan dan secara default, nilai apa pun dapat diteruskan ke prop apa pun. Dalam templat di atas, Anda akan melihat bahwa kami dapat mengakses nilai ini pada instance komponen, sama seperti dengan data.

Setelah prop terdaftar, Anda dapat mengoper data sebagai atribut khusus, seperti ini:

<blog-post title="Perjalanan saya dengan Vue"></blog-post>
<blog-post title="Blogging dengan Vue"></blog-post>
<blog-post title="Kenapa Vue sangat menyenangkan"></blog-post>

Namun, dalam aplikasi yang khas, Anda kemungkinan akan memiliki serangkaian pos dalam data:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'Perjalanan saya dengan Vue' },
      { id: 2, title: 'Blogging dengan Vue' },
      { id: 3, title: 'Mengapa Vue sangat menyenangkan' }
    ]
  }
})

Lalu ingin me-rendernya untuk setiap komponen:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

Di atas, Anda akan melihat bahwa kita dapat menggunakan v-bind secara dinamis menggunakan prop. Ini sangat berguna ketika Anda tidak tahu konten pasti yang akan Anda render sebelumnya, seperti saat mengambil posting dari API.

Itu saja yang perlu Anda ketahui tentang props untuk saat ini, tetapi setelah selesai membaca halaman ini dan merasa nyaman dengan isinya, kami sarankan untuk kembali lagi nanti untuk membaca panduan lengkap tentang Props.

Elemen Root Tunggal

Saat membuat komponen <blog-post>, templat Anda pada akhirnya akan berisi lebih dari sekedar judul:

<h3>{{ title }}</h3>

Setidaknya, Anda ingin memasukan posting konten:

<h3>{{ title }}</h3>
<div v-html="content"></div>

Jika Anda mencoba ini di templat Anda, Vue akan memunculkan kesalahan, menjelaskan bahwa setiap komponen harus memiliki elemen root tunggal. Anda bisa memperbaiki kesalahan ini dengan membungkus templat dalam elemen induk, seperti:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

Seiring komponen tumbuh, kemungkinan kita tidak hanya membutuhkan judul dan konten dari sebuah posting, tetapi juga tanggal diterbitkan, komentar, dan lainnya. Mendefinisikan prop untuk setiap informasi terkait bisa menjadi sangat menjengkelkan:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>

Jadi ini mungkin saat yang tepat untuk memperbaiki komponen <blog-post> untuk menerima prop post tunggal sebagai gantinya:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})

Contoh di atas dan beberapa yang akan datang menggunakan templat literal JavaScript untuk membuat templat beberapa baris sehingga lebih mudah dibaca. Ini tidak didukung oleh Internet Explorer (IE), jadi jika Anda harus mendukung IE dan tidak mentranspeksi (contohnya Babel atau TypeScript), gunakan lolos baris baru sebagai gantinya.

Sekarang, properti baru apapun akan di tambahkan ke objek post, itu akan otomatis ada didalam <blog-post>.

Memantau Events untuk Anak Komponen

Saat kita mengembangkan komponen <blog-post>, beberapa fitur mungkin membutuhkan komunikasi kembali ke induk. Sebagai contoh, kita mungkin memutuskan untuk memasukan fitur aksesibilitas untuk memperbesar text posting blog, sambil membiarkan sisa halaman ukuran defaultnya:

Didalam induk, kita akan mendukung fitur ini dengan menambahkan properti data postFontSize:

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

Yang dapat digunakan dalam templat untuk mengontrol ukuran font semua posting blog:

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

Sekarang mari kita tambahkan tombol untuk memperbesar teks tepat sebelum konten posting:

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Memperbesar teks
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

Masalahnya adalah, tombol ini tidak mendapatkan apa-apa:

<button>
  Memperbesar teks
</button>

Ketika kita mengklik tombol, kita perlu untuk berkomunikasi dengan induk bahwa itu harus memperbesar tulisan teks pada semua posting. Untung, Vue instances menyediakan sistem kustom events untuk menyelesaikan masalah ini. Induk dapat memilih untuk memantau event apa pun dengan instance anak komponen dengan v-on, sama seperti yang kita lakukan pada event DOM asli:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

Kemudian anak komponen dapat emit (mengeluarkan output) suatu event pada dirinya sendiri dengan memanggil metode $emit bawaan, mengoper nama dari event:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

Terima kasih kepada listener v-on:enlarge-text="postFontSize += 0.1", induk akan menerima event dan perbaruan isi postFontSize.

Meng-Emit Nilai dengan Event

Ini terkadang berguna untuk meng-emit nilai spesifik dengan event. Sebagai contohnya, kita mungkin menginginkan komponen <blog-post> bertanggung jawab atas seberapa banyak teks akan diperbesar. Dalam hal itu, kita akan menggunakan parameter ke-2 $emit untuk meng-emit nilai ini:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Memperbesar teks
</button>

Kemudian ketika kita memantau event di induk, kita dapat mengakses nilai event yang di berikan dengan $event:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

Atau, jika event handler adalah metode:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>

Kemudian nilai akan dikirimkan sebagai parameter pertama dari metode itu:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

Menggunakan v-model pada Komponent

Kustom events juga dapat digunakan untuk membuat kustom input yang berkerja dengan v-model. Ingat bahwa:

<input v-model="searchText">

hal yang sama dengan:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

Saat digunakan pada komponen, sebagai ganti v-model gunakan seperti ini:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

Agar ini benar-benar berfungsi, <input> di dalam komponen harus:

Di sinilah beraksi:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

Sekarang v-model seharusnya bekerja dengan sempurna dengan komponen ini:

<custom-input v-model="searchText"></custom-input>

Itu saja yang perlu Anda ketahui tentang kustom events komponen untuk saat ini, tetapi setelah selesai membaca halaman ini dan merasa nyaman dengan isinya, kami sarankan untuk kembali lagi nanti untuk membaca panduan lengkap tentang Custom Events.

Distribusi Konten dengan Slots

Sama seperti dengan elemen HTML, seringkali berguna untuk dapat mengoper konten ke komponen, seperti ini:

<alert-box>
  Sesuatu yang buruk telah terjadi.
</alert-box>

Yang mungkin me-render sesuatu seperti:

Sesuatu yang buruk telah terjadi.

Untungnya, tugas ini dibuat sangat sederhana oleh Vue kustom elemen <slot>:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Kesalahan!</strong>
      <slot></slot>
    </div>
  `
})

Sama seperti yang Anda lihat di atas, kita hanya menambahkan slot ke tempat yang kita inginkan – dan hanya itu. Dilakukan!

Itu saja yang perlu Anda ketahui tentang slots untuk saat ini, tetapi setelah selesai membaca halaman ini dan merasa nyaman dengan isinya, kami sarankan untuk kembali lagi nanti untuk membaca panduan lengkap tentang Slots.

Komponen Dinamis

Terkadang, berguna untuk secara dinamis beralih antar komponen, seperti di antarmuka tab.

Hal di atas dimungkinkan oleh elemen <component> Vue dengan spesial atribut is:

<!-- Komponen berubah ketika currentTabComponent berubah -->
<component v-bind:is="currentTabComponent"></component>

Dalam contoh di atas, currentTabComponent dapat berisi:

Lihat fiddle ini untuk bereksperimen dengan kode lengkap, atau versi ini untuk contoh yang mengikat ke opsi objek komponen, bukan nama yang terdaftar.

Itu saja yang perlu Anda ketahui tentang komponen dinamis untuk saat ini, tetapi setelah selesai membaca halaman ini dan merasa nyaman dengan isinya, kami sarankan untuk kembali lagi nanti untuk membaca panduan lengkap tentang Dinamis & Async Komponen.

Peringatan Parsing Templat DOM

Beberapa elemen HTML, seperti <ul>, <ol>, <table> dan <select> memiliki batasan pada elemen apa yang dapat muncul di dalamnya, dan beberapa elemen seperti <li>, <tr>, dan <option> hanya dapat muncul di dalam elemen lain tertentu.

ini akan menyebabkan masalah ketika menggunakan komponen dengan elemen yang memiliki batasan seperti itu. Sebagai contoh:

<table>
  <blog-post-row></blog-post-row>
</table>

Komponen khusus <blog-post-row> akan diangkat sebagai konten tidak valid, menyebabkan kesalahan pada hasil akhir yang diberikan. Untungnya, atribut spesial is menawarkan solusi:

<table>
  <tr is="blog-post-row"></tr>
</table>

Perlu dicatat bahwa keterbatasan ini tidak berlaku jika Anda menggunakan templat string dari salah satu sumber berikut:

Itu saja yang perlu Anda ketahui tentang peringatan parsing DOM templat untuk saat ini – dan sebenarnya, akhir dari hal-hal penting Vue. Selamat! Masih banyak yang harus dipelajari, tetapi pertama-tama, kami sarankan untuk beristirahat sejenak untuk bermain dengan Vue sendiri dan membuat sesuatu yang menyenangkan.

Setelah Anda merasa nyaman dengan pengetahuan yang baru saja Anda cerna, kami sarankan kembali untuk membaca panduan lengkap tentang Dinamis & Async Komponen, serta halaman lain di bagian in-Depth Komponen di bilah samping.