Chào mừng đến với Cafedev! Trong chủ đề Vue.js với Sự kiện của Component, chúng ta sẽ khám phá cách Vue.js xử lý sự kiện trong các component một cách linh hoạt và mạnh mẽ. Từ cách phát ra sự kiện đến cách lắng nghe và xử lý chúng, chúng ta sẽ tìm hiểu cách sử dụng Vue.js để tạo ra các ứng dụng web động với trải nghiệm người dùng tốt nhất. Hãy cùng học và chia sẻ kiến thức tại Cafedev!

Trang này giả định rằng bạn đã đọc hiểu Cơ bản về Components. Hãy đọc trước nếu bạn mới bắt đầu với các component.

1. Phát và Lắng nghe Sự kiện

Một component có thể phát sự kiện tùy chỉnh trực tiếp trong biểu thức mẫu (ví dụ trong một v-on handler) bằng cách sử dụng phương thức tích hợp $emit:

<!-- MyComponent -->
<button @click="$emit('someEvent')">click me</button>

Phương thức $emit() cũng có sẵn trên thể hiện của component dưới dạng this.$emit():

export default {
  methods: {
    submit() {
      this.$emit('someEvent')
    }
  }
}

Phía cha có thể lắng nghe nó bằng cách sử dụng v-on:

<MyComponent @some-event="callback" />

Modifier .once cũng được hỗ trợ trên người nghe sự kiện của component:

<MyComponent @some-event.once="callback" />

Giống như các component và props, tên sự kiện cung cấp một phương thức biến đổi tự động. Lưu ý rằng chúng tôi đã phát ra một sự kiện camelCase, nhưng có thể lắng nghe nó bằng cách sử dụng một người nghe kebab-cased trong phần cha. Như với props casing, chúng tôi khuyên bạn nên sử dụng người nghe sự kiện kebab-cased trong các mẫu.

TIPS: Khác với các sự kiện DOM native, các sự kiện được phát ra bởi component không lan truyền. Bạn chỉ có thể lắng nghe các sự kiện được phát ra bởi một component con trực tiếp. Nếu có nhu cầu giao tiếp giữa các component chị em hoặc được lồng sâu, hãy sử dụng một bus sự kiện bên ngoài hoặc một giải pháp quản lý trạng thái toàn cục.

2. Đối số Sự kiện

Đôi khi hữu ích khi phát ra một giá trị cụ thể với một sự kiện. Ví dụ, chúng ta có thể muốn component chịu trách nhiệm quyết định làm thế nào để phóng to văn bản. Trong những trường hợp đó, chúng ta có thể truyền đối số bổ sung cho $emit để cung cấp giá trị này:

<button @click="$emit('increaseBy', 1)">
  Increase by 1
</button>

Sau đó, khi chúng ta lắng nghe sự kiện trong phần cha, chúng ta có thể sử dụng một hàm mũi tên trực tiếp như là người nghe, cho phép chúng ta truy cập vào đối số của sự kiện:

<MyButton @increase-by="(n) => count += n" />

Hoặc, nếu bộ xử lý sự kiện là một phương thức:

<MyButton @increase-by="increaseCount" />

Sau đó, giá trị sẽ được chuyển như là tham số đầu tiên của phương thức đó:

function increaseCount(n) {
  count.value += n
}

tip: Tất cả các đối số bổ sung được truyền vào $emit() sau tên sự kiện sẽ được chuyển tiếp đến người nghe. Ví dụ, với $emit('foo', 1, 2, 3) hàm người nghe sẽ nhận được ba đối số.

3. Khai báo Sự kiện Phát ra

Một component có thể rõ ràng khai báo các sự kiện mà nó sẽ phát ra bằng cách sử dụng defineEmits() macro option:

<script setup>
defineEmits(['inFocus', 'submit'])
</script>

Phương thức $emit mà chúng ta đã sử dụng trong phần “<template>” không thể truy cập được trong phần <script setup> của một thành phần, nhưng defineEmits() trả về một hàm tương đương mà chúng ta có thể sử dụng thay thế.

<script setup>
const emit = defineEmits(['inFocus', 'submit'])

function buttonClick() {
  emit('submit')
}
</script>

Macro defineEmits() không thể được sử dụng bên trong một hàm, nó phải được đặt trực tiếp trong phần <script setup>, như trong ví dụ ở trên.

Nếu bạn đang sử dụng một hàm setup rõ ràng thay vì <script setup>, các sự kiện nên được khai báo bằng cách sử dụng tùy chọn emits, và hàm emit được tiết lộ trong ngữ cảnh setup().

export default {
  emits: ['inFocus', 'submit'],
  setup(props, ctx) {
    ctx.emit('submit')
  }
}

Như với các thuộc tính khác của ngữ cảnh setup(), emit có thể được giải tỏa một cách an toàn:

export default {
  emits: ['inFocus', 'submit'],
  setup(props, { emit }) {
    emit('submit')
  }
}

Tùy chọn emits và macro defineEmits() cũng hỗ trợ cú pháp đối tượng. Nếu sử dụng TypeScript, bạn có thể gõ loại đối số, cho phép chúng ta thực hiện kiểm tra thời gian chạy của dữ liệu của các sự kiện được phát ra:

<script setup lang="ts">
const emit = defineEmits({
  submit(payload: { email: string, password: string }) {
    // return `true` or `false` to indicate
    // validation pass / fail
  }
})
</script>

Nếu bạn đang sử dụng TypeScript với <script setup>, cũng có thể khai báo các sự kiện được phát ra bằng cách sử dụng chú thích kiểu tinh khiết:

<script setup lang="ts">
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>

Thêm chi tiết: Kiểu dữ liệu Sự kiện của Component

Mặc dù không bắt buộc, nhưng được khuyến nghị khai báo tất cả các sự kiện phát ra để tài liệu cách một component nên hoạt động như thế nào. Điều này cũng cho phép Vue loại trừ các người nghe đã biết từ các thuộc tính truyền qua, tránh các trường hợp biên do sự kiện DOM được gửi thủ công bởi mã của bên thứ ba.

TIPS: Nếu một sự kiện native (ví dụ, click) được định nghĩa trong tùy chọn emits, người nghe sẽ chỉ lắng nghe các sự kiện click được phát ra bởi component và không còn phản hồi lại các sự kiện click native nữa.

4. Xác thực Sự kiện

Tương tự như xác thực loại prop, một sự kiện phát ra có thể được xác thực nếu nó được định nghĩa với cú pháp đối tượng thay vì cú pháp mảng.
Để thêm xác thực, sự kiện được gán một hàm nhận các đối số được truyền vào cuộc gọi this.$emitemit và trả về một giá trị boolean để chỉ ra liệu sự kiện có hợp lệ hay không.

<script setup>
const emit = defineEmits({
  // No validation
  click: null,

  // Validate submit event
  submit: ({ email, password }) => {
    if (email && password) {
      return true
    } else {
      console.warn('Invalid submit event payload!')
      return false
    }
  }
})

function submitForm(email, password) {
  emit('submit', { email, password })
}
</script>

Hãy tiếp tục khám phá và áp dụng những kiến thức về xử lý sự kiện trong Vue.js mà bạn đã học được từ Cafedev. Chúng tôi hy vọng rằng thông qua việc áp dụng những kỹ thuật này, bạn sẽ có thể xây dựng những ứng dụng web động mạnh mẽ và linh hoạt hơn. Đừng ngần ngại thảo luận, chia sẻ ý kiến và học hỏi thêm trên Cafedev – nơi cộng đồng kỹ thuật sôi động và hỗ trợ. Cảm ơn bạn đã đồng hành và ủng hộ Cafedev!

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!