Slot và scoped slots trong Vue.js

Thông tường trong Vuejs chúng ta hay dùng prop để truyền data từ component cha sang component con. Thế nhưng đôi lúc chúng ta không muốn sử dụng prop mà chỉ muốn chèn nội dụng HTML vào bên trong component con giống như cách chúng ta viết HTML thông thường thì sao. Vue lại một lần nữa không để cho anh em thất vọng khi hỗ trợ làm việc này với Slot. Trong bài viết này chúng ta sẽ tìm hiểu về Slot và scoped slots trong Vue.js trong Vuejs các bạn nhé!

Cú pháp Slot trong Vuejs

Để chèn nội dung HTML từ component cha vào component con với slot chúng ta sử dụng cú pháp sau:

<slot></slot>

Ví dụ:

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

Các loại slot

Slot cơ bản

Dưới đây chúng ta sẽ tìm hiểu cách dùng căn bản của slot. Chúng ta có component con (component child) sử dụng slot như sau:

<div class="children">
  <h2>This is children component</h2>
  <slot></slot>
</div>

Component parent (components cha) chèn nội dung vào bên trong child

<div class="parent">
  <h2>This is parent component</h2>
  <child>
    <p>Hello from parent</p>
  </child>
</div>

Nội dung sau khi render ra như sau:

<div class="parent">
  <h2>This is parent component</h2>
  <div class="children">
    <h2>This is children component</h2>
    <p>Hello from parent</p>
  </div>
</div>

Fallback content

Tất cả nội dung bên trong <slot></slot> sẽ được dùng làm fallback content khi component cha không chèn bất kì thứ gì vào component con.

Ví dụ:

<div class="children">
  <h2>This is children component</h2>
  <slot><p>Đây là nội dung trong slot</p></slot>
</div>

Component cha gọi tới child nhưng không chèn nội dung vào:

<div class="parent">
  <h2>Đây là phần tử cha</h2>
  <child></child>
</div>

Kết quả khi render ra sẽ hiển thị nội dung fallback:

<div class="parent">
  <h2>This is parent component</h2>
  <div class="children">
    <h2>Đây là phần tử cha</h2>
    <p>Đây là nội dung trong slot</p>
  </div>
</div>

Slot được đặt tên

slot trong vuejs có một thuộc tính đặc biệt là name hỗ trợ chúng ta có thể đặt tên cho slot đó. Trong một component có thể chứa nhiều slot  với tên khác nhau và Vue.js cũng cho phép có một slot   không được đặt tên để chứa những nội dung không trùng khớp với bất kì slot name nào trong component. Chúng ta cùng xem ví dụ dưới đây cho trực quan dễ hiểu.

Ta có một componet card gồm 3 phần headercontentfooter Ta sẽ đặt vào 3 slot như sau:

<!-- Component card -->
<div class="card">
  <header class="card-header">
    <slot name="header"></slot>
  </header>
  <div class="card-content">
    <slot></slot>
  </div>
  <footer class="card-footer">
    <slot name="footer"></slot>
  </footer>
</div>

Component cha sử dụng và truyền nội dung:

<div class="parent">
 <card>
   <h2 slot="header">Vue.js thật tuyệt vời a mây zing goodjob</h2>
   <p>Framework JavaScript mạnh mẽ</p>
   <p>Một sản phẩm</p>
   <p slot="footer">Tạo ra bởi Evan You</p>
 </card>
</div>

Kết quả render:

<!-- Component card -->
<div class="card">
  <header class="card-header">
    <slot name="header"></slot>
  </header>
  <div class="card-content">
    <slot></slot>
  </div>
  <footer class="card-footer">
    <slot name="footer"></slot>
  </footer>
</div>
<div class="parent">
 <card>
   <h2 slot="header">Vue.js thật tuyệt vời a mây zing goodjob</h2>
   <p>Framework JavaScript mạnh mẽ</p>
   <p>Một sản phẩm</p>
   <p slot="footer">Tạo ra bởi Evan You</p>
 </card>
</div>

Scoped slots

Scoped slots là một loại đặt biệt của slot giúp bạn có thể truyền dữ liệu từ component con lên component cha thông qua việc gán dữ liệu thông qua thuộc tính (nó cũng tương tự việc đưa dữ liệu vào props của component vậy). Chúng ta cùng xem qua ví dụ:

Mình có một child như sau:

<div class="children">
  <slot text="Hello from child!"></slot>
</div>

Như các bạn thấy, mình truyền vào slot một attribute là text kiểu như prop bạn thường thấy khi truyền vào component.

Tiếp theo đến component cha. Chúng ta sẽ lấy nội dung từ text thông qua thuộc tính slot-scope

<div class="parent">
  <p>Hello from parent</p>
  <child>
    <p slot-scope="props" v-text="props.text"></p>
  </child>
</div>

<!-- Hoặc có thể dùng tính năng destructuring syntax của ES2015 -->

<p slot-scope="{ text }" v-text="text"></p>

Những kiểu dữ liệu có thể sử dụng trong scoped slots có thể là stringnumberobjectarray thậm chí bạn có thể truyền method.

3. Tổng kết

Cách dùng slot trong Vuejs thực ra rất đơn giản tuy nhiên thông thường nó chỉ được dùng để truyền data đơn giản, còn phức tạp hơn chúng ta vẫn phải dùng prod các bạn nhé. Chúc các bạn hộc tốt!

Bình luận