- Pelajari
-
Ekosistem
Pertolongan
Alat
Pustaka Inti
Berita
Daftar Sumber Daya
- Tim
- Dukung Vue
- Terjemahan
Petunjuk
Esensial
- Instalasi
- Perkenalan
- Vue Instance
- Sintaks Templat
- Properti Penghitung (Computed) dan Pengamat (Watchers)
- Kelas and Binding Gaya
- Rendering Bersyarat
- Me-render Daftar
- Penanganan Event
- Form Input Bindings
- Komponen Dasar
Komponen secara mendalam
- Registrasi Komponen
- Props
- Custom Events
- Slot
- Komponen yang Dinamis & Async
- Menangani Kasus Langka
Transisi & Animasi
- Transisi Masuk/Keluar & Daftar Transisi
- Transisi State
Kebergunaan & Komposisi
- Mixins
- Direktif Kustom
- Fungsi Render & JSX
- Plugin
- Filter
Peralatan
- Komponen Berkas Tunggal
- Unit Testing
- Dukungan TypeScript
- Penempatan Produksi
Peningkatan
- Routing
- Pengelolaan State
- Rendering di Sisi Server (SSR)
Internal
- Reaktivitas Secara Mendalam
Migrasi
- Migrasi dari Vue 1.x
- Migrasi dari Vuex 0.6.x ke 1.0
Meta
- Perbandingan dengan Kerangka Kerja yang Lain
- Gabung Komunitas Vue.js!
- Tim Inti Vuejs
Slot
Sebelum mulai membaca halaman ini, kami berasumsi bahwa Anda telah membaca Dasar-Dasar Komponen. Baca halaman itu terlebih dahulu bila Anda belum mengerti tentang komponen.
Di versi 2.6.0, kami memperkenalkan sintaks baru (direktif
v-slot
) untuk nama dan slot scope. Sintaks tersebut menggantikanslot
dan atributslot-scope
, yang sekarang tidak digunakan lagi, tapi masih belum dihapus dan masih didokumentasikan di sini. Alasan kami untuk memperkenalkan sintaks baru dapat dilihat di RFC.
Konten Slot
Vue mengimplementasikan API distribusi konten yang terinspirasi dari Draf Spesifikasi Komponen Web, dan elemen <slot>
dapat digunakan sebagai outlet distribusi untuk konten kita.
Ini memungkinkan Anda untuk membuat komponen seperti ini:
<navigation-link url="/profile">
Profil Anda
</navigation-link>
Kemudian di templat <navigation-link>
, Anda mungkin memiliki templat seperti ini:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
Ketika komponen di-render, <slot></slot>
akan menggantinya dengan “Profil Anda”. Elemen slot dapat berisi kode templat apa saja, termasuk HTML:
<navigation-link url="/profile">
<!-- Menambahkan ikon Font Awesome -->
<span class="fa fa-user"></span>
Profil Anda
</navigation-link>
Atau bahkan dapat berisi komponen lain:
<navigation-link url="/profile">
<!-- Menggunakan komponen untuk menambahkan ikon -->
<font-awesome-icon name="user"></font-awesome-icon>
Profil Anda
</navigation-link>
Jika templat <navigation-link>
tidak berisi elemen <slot>
, konten apapun yang kita sediakan di dalam komponen <navigation-link>
akan di buang.
Kompilasi Scope
Saat Anda ingin menggunakan data di dalam slot, seperti ini:
<navigation-link url="/profile">
Masuk sebagai {{ user.name }}
</navigation-link>
Slot dapat mengakses properti instance yang sama (scope yang sama). Slot tidak dapat mengakses ke scope <navigation-link>
. Misalnya, Anda mencoba untuk mengakses data url
dari scope <navigation-link>
, itu tidak akan bisa:
<navigation-link url="/profile">
Klik di sini dan Anda akan diarahkan ke: {{ url }}
<!--
Data `url` akan *undefined*, karena tidak di definisikan _di dalam_ komponen
<navigation-link>, tetapi data `url` akan dioper _ke_ templat <navigation-link>.
-->
</navigation-link>
Ingat, bahwa aturannya:
Semua yang ada di templat induk, akan dikompilasi di dalam scope induk; semua yang ada di templat anak, akan dikompilasi di dalam scope anak.
Konten Fallback
Ada beberapa kasus yang bermanfaat untuk menentukan konten slot fallback (slot default), yang hanya akan di-render ketika tidak ada konten yang tersedia. Misalnya, di dalam komponen <submit-button>
:
<button type="submit">
<slot></slot>
</button>
Kita mungkin ingin merender teks “Submit” di dalam <button>
setiap saat. Untuk membuatnya, kita dapat menempatkan teks “Submit” di antara tag <slot>
:
<button type="submit">
<slot>Submit</slot>
</button>
Sekarang saat kita menggunakan <submit-button>
di dalam komponen induk, yang tidak kita sediakan konten di dalamnya:
<submit-button></submit-button>
Komponen tersebut akan merender konten fallback (default) yang telah kita sediakan sebelumnya:
<button type="submit">
Submit
</button>
Akan tetapi jika kita menyediakan konten di komponen tersebut:
<submit-button>
Save
</submit-button>
Konten tersebut akan di-render sebagai:
<button type="submit">
Save
</button>
Slot yang Memiliki Nama (Named Slot)
Diperbarui di versi 2.6.0+. Lihat di sini untuk sintaks yang tidak digunakan lagi, yang menggunakan atribut
slot
.
Ada kalanya memiliki banyak slot itu bermanfaat. Misalnya, di dalam komponen <base-layout>
dengan templat berikut ini:
<div class="container">
<header>
<!-- Kita ingin konten *header* di sini -->
</header>
<main>
<!-- Kita ingin konten *main* di sini -->
</main>
<footer>
<!-- Kita ingin konten *footer* di sini -->
</footer>
</div>
Pada kasus ini, elemen <slot>
memiliki atribut khusus, name
, yang dapat digunakan untuk mendefinisikan slot tambahan:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<slot>
tanpa menggunakan name
secara implisit memiliki nama “default”.
Untuk menyediakan konten di slot yang memiliki nama, kita dapat menggunakan direktif v-slot
di <template>
yang menggunakan nama slot sebagai argumen v-slot
:
<base-layout>
<template v-slot:header>
<h1>Di sini mungkin untuk judul halaman</h1>
</template>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
<template v-slot:footer>
<p>Di sini untuk beberapa info kontak</p>
</template>
</base-layout>
Sekarang semua yang ada di dalam templat <template>
akan dioper ke slot yang sesuai. Konten apa pun yang tidak di bungkus dengan <template>
yang menggunakan atribut v-slot
, itu akan diasumsikan sebagai slot default.
Namun, jika Anda ingin lebih eksplisit, Anda masih bisa membungkus konten slot default di dalam <template>
:
<base-layout>
<template v-slot:header>
<h1>Di sini mungkin untuk judul halaman</h1>
</template>
<template v-slot:default>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
</template>
<template v-slot:footer>
<p>Di sini untuk beberapa info kontak</p>
</template>
</base-layout>
Jika tidak, HTML yang kita tempatkan di antara templat <template>
akan di-render seperti ini:
<div class="container">
<header>
<h1>Di sini mungkin untuk judul halaman</h1>
</header>
<main>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
</main>
<footer>
<p>Di sini untuk beberapa info kontak</p>
</footer>
</div>
Perhatikan bahwa v-slot
hanya dapat ditambahkan di <template>
(dengan satu pengecualian), tidak seperti atribut slot
yang tidak digunakan lagi.
Scope Slot
Diperbarui di versi 2.6.0+. Lihat di sini untuk sintaks yang tidak digunakan lagi, yang menggunakan atribut
slot-scope
.
Terkadang, konten slot yang hanya memiliki akses ke data yang tersedia di komponen anak, itu sangat berguna. Misalnya, bayangkan jika komponen <current-user>
dengan templat berikut ini:
<span>
<slot>{{ user.lastName }}</slot>
</span>
Ingin kita ganti dengan komponen fallback (default) dengan nama depan pengguna, seperti ini:
<current-user>
{{ user.firstName }}
</current-user>
Itu tidak akan bisa, karena komponen <current-user>
hanya dapat mengakses data user
dan konten yang kita sediakan di-render di induk.
Untuk membuat data user
tersedia di induk konten slot, kita bisa bind data user
sebagai atribut di elemen <slot>
:
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
Atribut yang di-bind di elemen <slot>
yang memiliki nama slot props. Sekarang di scope induk, kita dapat menggunakan v-slot
dengan nilai untuk mendefinisikan nama slot props yang telah kita sediakan:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
Di contoh ini, kita memilih untuk memberi nama objek yang berisi semua slot props slotProps
kami, tetapi Anda bisa menggunakan nama apa pun yang Anda suka.
Sintaks yang Disingkat untuk Slot Default yang Sendirian
Pada kasus di atas, ketika slot default saja yang hanya disediakan konten, tag komponen dapat digunakan sebagai templat slot. Ini memungkinkan kita untuk menggunakan v-slot
secara langsung di komponen:
<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</current-user>
Ini bisa dipersingkat, bahkan bisa lebih. Sama seperti konten yang tidak ditentukan, v-slot
tanpa argumen dapat diasumsikan merujuk ke slot default:
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
</current-user>
Perhatikan bahwa sintaks yang disingkat untuk slot default yang sendirian tidak bisa dicampur dengan slot yang memiliki nama, karena akan menyebabkan scope yang ambigu:
<!-- TIDAK VALID, dan akan menghasilkan peringatan -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps TIDAK tersedia di sini
</template>
</current-user>
Setiap kali ada banyak slot, pastikan untuk menggunakan sintaks <template>
pada semua slot:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</current-user>
Destrukturisasi Props Slot
Dibelakang, cara slot scope bekerja adalah dengan membungkus konten slot Anda di dalam suatu function yang melewati satu argumen:
function (slotProps) {
// ... slot content ...
}
Itu berarti, nilai v-slot
sebenarnya dapat menerima ekspresi JavaScript yang valid yang berada di posisi argumen dari definisi function. Jadi, di lingkungan yang didukung (komponen berkas tunggal (single-file components) atau browser moderen), Anda juga bisa menggunakan Destrukturisasi ES2015 untuk mengeluarkan slot props yang spesifik, seperti ini:
<current-user v-slot="{ user }">
{{ user.firstName }}
</current-user>
Ini bisa membuat templat menjadi lebih bersih, terutama ketika slot menyediakan banyak props. Ini juga membuka kemungkinan lain, seperti mengganti nama props, Contohnya nama user
diganti menjadi person
:
<current-user v-slot="{ user: person }">
{{ person.firstName }}
</current-user>
Anda bahkan dapat mendefinisikan fallbacks, untuk di gunakan ketika slot props tidak didefinisikan:
<current-user v-slot="{ user = { firstName: 'Guest' } }">
{{ user.firstName }}
</current-user>
Nama Slot yang Dinamis
Baru di versi 2.6.0+
Argumen direktif yang dinamis juga bekerja di v-slot
, itu memungkinkan Anda untuk mendefinisikan nama slot secara dinamis:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
Nama Slot yang Disingkat
Baru di versi 2.6.0+
Sama seperti v-on
dan v-bind
, v-slot
juga memiliki nama yang disingkat, mengganti semua argumen sebelum (v-slot:
) dengan simbol khusus #
. Misalnya, v-slot:header
bisa ditulis ulang sebagai #header
:
<base-layout>
<template #header>
<h1>Di sini mungkin untuk judul halaman</h1>
</template>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
<template #footer>
<p>Di sini untuk beberapa info kontak</p>
</template>
</base-layout>
Namun, seperti halnya dengan direktif, nama yang disingkat hanya tersedia saat argumen telah disediakan. Itu berarti sintaks berikut ini tidak valid:
<!-- Ini akan memicu peringatan -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>
Sebagai gantinya, Anda harus selalu menentukan nama slot jika Anda ingin menggunakan nama yang disingkat:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>
Contoh Lainnya
Slot props memungkinkan kita untuk mengubah slot menjadi templat yang dapat digunakan kembali, dan bisa di-render dengan konten yang berbeda, yang berbasis pada input props. Ini sangat berguna ketika Anda mendesain komponen yang dapat digunakan kembali yang merangkum logika data, yang memungkinkan komponen induk untuk mengkonsumsi data tersebut, untuk mengkustomisasi layout.
Misalnya, kami sedang mengimplementasikan komponen <todo-list>
yang berisi layout dan logika filter untuk list:
<ul>
<li
v-for="todo in filteredTodos"
v-bind:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
Daripada hard-coding setiap konten todo, kita bisa membiarkan komponen induk untuk membuat setiap slot todo, kemudian bind todo
sebagai slot props:
<ul>
<li
v-for="todo in filteredTodos"
v-bind:key="todo.id"
>
<!--
Kita mimiliki *slot* untuk setiap `todo`, kemudian oper objek `todo` sebagai *slot props*.
-->
<slot name="todo" v-bind:todo="todo">
<!-- Konten fallback (*default*) -->
{{ todo.text }}
</slot>
</li>
</ul>
Sekarang saat kita menggunakan komponen <todo-list>
, secara opsional kita bisa mendifinisikan alternatif <template>
untuk todo items, tapi dengan akses ke data dari anak:
<todo-list v-bind:todos="todos">
<template v-slot:todo="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>
Namun, ini bahkan nyaris tidak menjelaskan apa saja yang bisa slot lakukan. Di dunia nyata, contoh yang bagus untuk penggunaan slot, kami sarankan untuk menelusuri pustaka seperti Vue Virtual Scroller, Vue Promised, dan Portal Vue.
Sintaks yang tidak digunakan lagi
Direktif
v-slot
diperkenalkan di Vue versi 2.6.0, menawarkan API alternatif yang telah ditingkatkan, yang masih mendukung atributslot
danslot-scope
. Alasan lengkap diperkenalkannyav-slot
dapat dilihat di RFC. Atributslot
danslot-scope
akan terus didukung di semua rilis Vue 2.x mendatang, tetapi secara resmi tidak digunakan lagi dan akhirnya akan dihapus di Vue 3.
Slot yang Memiliki Nama dengan Atribut slot
Tidak digunakan lagi di versi 2.6.0+. Lihat di sini untuk sintaks baru yand direkomendasikan.
Untuk mengoper konten ke slot yang memiliki nama dari induk, gunakan atribut khusus slot
di <template>
(menggunakan komponen <base-layout>
yang dijelaskan di bawah ini sebagai contoh):
<base-layout>
<template slot="header">
<h1>Di sini mungkin untuk judul halaman</h1>
</template>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
<template slot="footer">
<p>Di sini untuk beberapa info kontak</p>
</template>
</base-layout>
Atau, atribut slot
yang juga bisa digunakan secara langsung di elemen normal:
<base-layout>
<h1 slot="header">Di sini mungkin untuk judul halaman</h1>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
<p slot="footer">Di sini untuk beberapa info kontak</p>
</base-layout>
Masih ada satu slot yang tidak memiliki nama, yang merupakan slot default, yang berfungsi untuk menangkap semua konten yang tidak cocok. Di dalam dua contoh di atas, HTML akan di-render menjadi:
<div class="container">
<header>
<h1>Di sini mungkin untuk judul halaman</h1>
</header>
<main>
<p>Paragraf untuk konten utama</p>
<p>Dan satu lagi</p>
</main>
<footer>
<p>Di sini untuk beberapa info kontak</p>
</footer>
</div>
Scope Slot dengan Atribut slot-scope
Tidak digunakan lagi di versi 2.6.0+. Lihat di sini untuk sintaks baru yand direkomendasikan.
Untuk menerima props yang dioper ke slot, komponen induk juga bisa menggunakan <template>
dengan atribut slot-scope
(menggunakan <slot-example>
yang dijelaskan di bawah ini sebagai contoh):
<slot-example>
<template slot="default" slot-scope="slotProps">
{{ slotProps.msg }}
</template>
</slot-example>
Di sini, slot-scope
menerima objek props sebagai variabel slotProps
, dan membuatnya tersedia di dalam scope <template>
. Anda dapat memberi nama slotProps
apa pun yang Anda suka, sama seperti memberi nama argumen function di JavaScript.
Di sini, slot="default"
dapat dihilangkan karena tersirat:
<slot-example>
<template slot-scope="slotProps">
{{ slotProps.msg }}
</template>
</slot-example>
Atribut slot-scope
juga bisa digunakan secara langsung di elemen yang non-<template>
(termasuk komponen):
<slot-example>
<span slot-scope="slotProps">
{{ slotProps.msg }}
</span>
</slot-example>
Nilai slot-scope
dapat menerima ekspresi JavaScript yang valid yang berada di posisi argumen dari definisi function. Itu berarti, di lingkungan yang didukung (komponen berkas tunggal (single-file components) atau browser moderen), Anda juga bisa menggunakan Destrukturisasi ES2015 di dalam expresi seperti ini:
<slot-example>
<span slot-scope="{ msg }">
{{ msg }}
</span>
</slot-example>
Menggunakan <todo-list>
yang dijelaskan di bawah ini sebagai contoh, inilah cara penggunaan slot-scope
:
<todo-list v-bind:todos="todos">
<template slot="todo" slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>