Quay lại

Slots trong Vue.js là một cơ chế mạnh mẽ cho phép bạn chèn nội dung vào các component cha từ các component con một cách linh hoạt. Bằng cách này, bạn có thể tạo ra các component tái sử dụng mà không cần quan tâm đến nội dung cụ thể mà chúng sẽ chứa.

Khi bạn định nghĩa một slot trong một component, bạn tạo ra một vùng chứa cho nội dung mà bạn muốn chèn từ bên ngoài. component cha sẽ quyết định nội dung cụ thể sẽ được chèn vào slot đó. Điều này cho phép bạn tạo ra các component cha linh hoạt có thể chứa nội dung khác nhau từ các component con.

Có một số tình huống khi bạn nên sử dụng slot trong Vue.js:

  1. Khi bạn muốn tái sử dụng một component với nội dung khác nhau: Slot cho phép bạn chèn nội dung từ bên ngoài vào một component. Điều này rất hữu ích khi bạn muốn sử dụng một component nhưng muốn điều chỉnh nội dung của nó tùy thuộc vào ngữ cảnh.

  2. Khi bạn muốn tạo component cha linh hoạt: Sử dụng slot cho phép bạn tạo ra các component cha mà không cần quan tâm đến nội dung cụ thể mà chúng sẽ chứa. Thay vào đó, nội dung của component cha có thể được xác định từ bên ngoài thông qua slot.

  3. Khi bạn muốn tạo các component dựa trên mẫu: Slot cho phép bạn xác định các điểm chèn nội dung trong một component. Điều này giúp bạn tạo ra các mẫu component mà có thể được sử dụng để tạo ra các giao diện phức tạp từ các phần nhỏ hơn.

  4. Khi bạn muốn chia sẻ dữ liệu hoặc trạng thái giữa các component cha và con: Slot cung cấp một cách để truyền dữ liệu từ component cha vào component con thông qua các props hoặc biến trạng thái.

  5. Khi bạn muốn tạo ra các component có thể mở rộng: Slot cho phép các component con mở rộng và điều chỉnh component cha mà chúng được chèn vào, tạo ra một cách để tạo ra các component có khả năng thích ứng và linh hoạt.

Nhớ rằng không phải lúc nào cũng cần sử dụng slot. Nếu bạn đang làm việc với các component đơn giản hoặc không cần sự linh hoạt cao, thì việc sử dụng props có thể là lựa chọn tốt hơn. Tuy nhiên, slot là một công cụ mạnh mẽ khi bạn cần tính linh hoạt và tái sử dụng cao hơn trong ứng dụng của mình.

Giả sử bạn có một component Button trong Vue.js để tạo nút với các thuộc tính và sự kiện tùy chỉnh:

<template>
  <button :class="btnClass" @click="handleClick">
    <slot></slot>
  </button>
</template>

<script>
export default {
  props: {
    btnClass: {
      type: String,
      default: "btn-primary"
    }
  },
  methods: {
    handleClick() {
      // Xử lý sự kiện khi nút được nhấn
      this.$emit("click");
    }
  }
};
</script>

Trong ví dụ trên, chúng ta đã sử dụng một slot để chèn nội dung bên trong Button. Bây giờ, bạn có thể sử dụng component Button này như sau:

<template>
  <div>
    <Button btnClass="btn-primary" @click="handlePrimaryButtonClick">
      Primary Button
    </Button>
    <Button btnClass="btn-secondary" @click="handleSecondaryButtonClick">
      Secondary Button
    </Button>
  </div>
</template>

<script>
import Button from "@/components/Button.vue";

export default {
  components: {
    Button
  },
  methods: {
    handlePrimaryButtonClick() {
      console.log("Primary button clicked");
    },
    handleSecondaryButtonClick() {
      console.log("Secondary button clicked");
    }
  }
};
</script>

Ở đây, bạn có thể thấy chúng ta đã sử dụng component Button với các nội dung khác nhau ("Primary Button" và "Secondary Button"), nhưng vẫn tái sử dụng cùng một component Button.Điều này làm cho mã của bạn dễ bảo trì và linh hoạt hơn.

Named Slots

Named slots trong Vue.js cho phép bạn đặt tên cho các slot trong component con, cho phép các component cha xác định nơi chèn nội dung dựa trên tên của slot đó. Điều này làm cho việc chèn nội dung trở nên linh hoạt hơn và cho phép bạn quản lý các phần của nội dung một cách hiệu quả hơn.

Dưới đây là một ví dụ minh họa về cách sử dụng named slots trong Vue.js:

<!-- Thành phần con với các named slots -->
<template>
  <div>
    <h2>Thành phần Con</h2>
    <!-- Đặt tên cho các slot -->
    <header v-if="$slots.title">
      <slot name="title"></slot>
   </header>
    <slot name="content"></slot>
  </div>
</template>

<script>
 export default {
  mounted() {
    console.log(this.$slots.title);
  },
 }
</script>
<!-- Thành phần cha -->
<template>
  <div>
    <h2>Thành phần Cha</h2>
    <SlotExample>
      <!-- Chèn nội dung vào các slot được đặt tên -->
      <template v-slot:title>
        <h3>Tiêu đề</h3>
      </template>
      <template v-slot:content>
        <p>Nội dung</p>
      </template>
    </SlotExample>
  </div>
</template>

<script>
import SlotExample from '@/components/SlotExample.vue';

export default {
  components: {
    SlotExample
  }
};
</script>

Trong ví dụ này, component cha SlotExample chứa hai named slots: một là title và một là content. Trong khi định nghĩa nội dung trong component cha, chúng ta sử dụng các thẻ <template> để xác định tên của slot mà nội dung sẽ được chèn vào. Điều này giúp chúng ta kiểm soát được nơi chèn nội dung trong các named slots của component con.

Named slots hữu ích khi bạn cần chia nhỏ nội dung vào các phần khác nhau và quản lý chúng một cách linh hoạt, đặc biệt là khi xây dựng các component phức tạp.

Một cách nữa bạn có thể xác định tên của slot mà nội dung sẽ được chèn vào đó là dùng dấu "#"

<SlotExample>
  <!-- Chèn nội dung vào các slot được đặt tên -->
  <template #title>
    <h3>Tiêu đề</h3>
  </template>
  <template #content>
    <p>Nội dung</p>
  </template>
</SlotExample>

Slot Styles & Compilation

Trong Vue.js, bạn có thể áp dụng các kiểu CSS cho nội dung được chèn vào các slot bằng cách sử dụng các cơ chế như scoped CSS hoặc CSS module. Dưới đây là cách bạn có thể thực hiện điều này:

Scoped CSS

Scoped CSS cho phép bạn xác định các kiểu CSS chỉ áp dụng cho phần HTML của component hiện tại và không ảnh hưởng đến các component khác trong ứng dụng của bạn. Điều này giúp tránh xung đột và làm cho mã của bạn dễ bảo trì hơn.

<!-- Thành phần cha -->
<template>
  <div>
    <h2>Thành phần Cha</h2>
    <SlotExample>
      <!-- Chèn nội dung vào slot -->
      <p slot="content">Nội dung được chèn vào slot.</p>
    </SlotExample>
  </div>
</template>

<script>
import SlotExample from '@/components/SlotExample.vue';

export default {
  components: {
    SlotExample
  }
};
</script>

<style scoped>
/* Kiểu CSS chỉ áp dụng cho thành phần cha */
p {
  color: blue;
}
</style>​
<!-- Thành phần con với named slot -->
<template>
  <div>
    <h2>Thành phần Con</h2>
    <slot name="content"></slot>
  </div>
</template>

<script>
export default {
};
</script>​

CSS Modules

CSS Modules là một cách khác để áp dụng CSS chỉ cho một phần của ứng dụng của bạn, đặc biệt là khi làm việc với các tệp CSS lớn. Khi sử dụng CSS modules, Vue.js tự động tạo ra các tên lớp CSS duy nhất cho mỗi component, giúp tránh xung đột giữa các kiểu CSS.

<!-- Thành phần cha -->
<template>
  <div>
    <h2>Thành phần Cha</h2>
    <SlotExample>
      <!-- Chèn nội dung vào slot -->
      <p slot="content">Nội dung được chèn vào slot.</p>
    </SlotExample>
  </div>
</template>

<script>
import SlotExample from '@/components/SlotExample.vue';

export default {
  components: {
    SlotExample
  }
};
</script>

<style module>
/* Kiểu CSS được sử dụng với CSS module */
p {
  color: blue;
}
</style>​
<!-- Thành phần con với named slot -->
<template>
  <div>
    <h2>Thành phần Con</h2>
    <slot name="content"></slot>
  </div>
</template>

<script>
export default {
};
</script>

<style module>
/* Kiểu CSS được sử dụng với CSS module */
p {
  font-weight: bold;
}
</style>​

Trong các ví dụ trên, chúng ta đã sử dụng scoped CSS và CSS modules để áp dụng kiểu CSS cho nội dung được chèn vào các slot trong Vue.js. Điều này giúp kiểm soát kiểu CSS và tránh xung đột giữa các component khác nhau của ứng dụng của bạn.

Scoped slots

Scoped slots trong Vue.js cho phép bạn truy cập vào dữ liệu và phương thức từ component cha trong component con thông qua các slots.

Dưới đây là một ví dụ minh họa về cách sử dụng scoped slots trong Vue.js:

component cha

<template>
  <div>
    <ListGoal #default="slotProps">
      <h2>{{ slotProps.item }}</h2>
      <p>{{ slotProps.anotherProp}}</p>
    </ListGoal>
  </div>
</template>

<script>

import ListGoal from './components/ListGoal.vue';

export default {
  components: {
    ListGoal
  },
};
</script>

<style>
  html {
    font-family: sans-serif;
  }

  body {
    margin: 0;
  }
</style>

component con:

<template>
    <ul>
        <li v-for="(goal) in goals" :key="goal">
            <slot :item="goal" another-prop="..."></slot>
        </li>
    </ul>
</template>

<script>

export default {
    data() {
        return {
            goals: ['Goal 1', 'Goal 2']
        }
    },
}
</script>

Đoạn mã trên hiển thị một danh sách các mục mục tiêu (goals) trong một component ListGoal. component này chứa một slot mặc định (#default) để chèn nội dung vào mỗi mục mục tiêu.

  • Trong phần ListGoal của component cha:

    • Sử dụng ListGoal và chèn nội dung vào slot mặc định (#default) của nó.
    • Trong slot, hiển thị tiêu đề của mỗi mục mục tiêu (slotProps.item) và một thuộc tính khác (slotProps.anotherProp) của mỗi mục mục tiêu.
  • Trong phần ListGoal của component con:

    • Hiển thị một danh sách ul.
    • Sử dụng v-for để lặp qua mỗi mục mục tiêu trong mảng goals.
    • Cho mỗi mục mục tiêu, chèn nội dung vào slot và truyền mục mục tiêu đó vào dưới dạng một prop được gọi là "item". Ngoài ra, bạn cũng có thể thấy thuộc tính khác được truyền là "another-prop".

Với cách này, mỗi mục mục tiêu trong danh sách goals có thể được hiển thị một cách linh hoạt và có thể tùy chỉnh nội dung bên trong một cách dễ dàng từ phía component cha.

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday