import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/vi/functional/Classes/EventRef - Trình quản lý sự kiện phản ứng'/>

# Lớp EventRef

Trình quản lý trình nghe sự kiện có tính phản ứng, giúp đơn giản hóa việc gắn và gỡ bỏ các sự kiện cho các thành phần DOM hoặc đối tượng `window`. Nó tự động cập nhật các đăng ký khi thành phần mục tiêu (được cung cấp dưới dạng Vue `Ref`) thay đổi.

Bao gồm việc tự động liên kết lại các trình nghe trong quá trình thay đổi thành phần động và tích hợp hoàn toàn với vòng đời của Vue.

## Các tính năng chính

- **Tính phản ứng** — tự động cập nhật khi thành phần `Ref` thay đổi.
- **Hỗ trợ đa loại** — nghe nhiều loại sự kiện cùng một lúc.
- **Tự động dọn dẹp** — quản lý bộ nhớ hiệu quả thông qua hệ thống phản ứng.

## Khởi tạo

Tạo một thực thể `EventRef` mới. Lớp này tự động đồng bộ hóa các trình lắng nghe sự kiện với trạng thái của Vue `ref` được truyền vào. Nếu phần tử đích thay đổi, `EventRef` sẽ tự động liên kết lại sự kiện.

### Ràng buộc Generic (Generic Constraints)

- `E extends ElementOrWindow` — kiểu của phần tử đích (ví dụ: `HTMLElement`, `Window`, hoặc `Document`).
- `O extends Event` — kiểu của đối tượng sự kiện (ví dụ: `MouseEvent`, `KeyboardEvent`).
- `D extends Record<string, any>` — kiểu dữ liệu tùy chỉnh (`detail`) gắn liền với sự kiện.

**Tham số:**
- `elementSelector?: RefOrNormal<ElementOrString<E> | undefined>` — phần tử đích hoặc bộ chọn (có thể ở dạng phản ứng).
- `elementSelectorControl?: RefOrNormal<ElementOrString<HTMLElement>>` — phần tử điều khiển. Nếu phần tử này bị xóa khỏi DOM, việc lắng nghe sẽ dừng lại.
- `type: string | string[] = ['click']` — loại sự kiện hoặc mảng các loại sự kiện.
- `listener?: EventListenerDetail<O, D>` — hàm xử lý.
- `options?: EventOptions` — các tùy chọn trình lắng nghe (`capture`, `passive`, `once`).
- `detail?: D` — dữ liệu bổ sung của sự kiện.

```typescript
import { EventRef } from '@dxtmisha/functional'
import { ref, onMounted, onUnmounted } from 'vue'

// 1. Khởi tạo đơn giản với Ref
const buttonRef = ref<HTMLButtonElement>()
const event = new EventRef(buttonRef, undefined, 'click', (e) => {
  console.log('Nút đã được nhấn:', e.target)
})

// 2. Sử dụng nhiều sự kiện và tùy chọn
const scrollEvent = new EventRef(
  window, 
  undefined, 
  ['scroll', 'resize'], 
  () => console.log('Cửa sổ đã thay đổi'),
  { passive: true }
)

onMounted(() => {
  event.start()
  scrollEvent.start()
})

onUnmounted(() => {
  event.stop()
  scrollEvent.stop()
})
```

## Vòng đời & Điều khiển

Các phương thức để kiểm soát hoạt động của trình lắng nghe.

- `start(): this` — Kích hoạt lắng nghe sự kiện. Nếu phần tử đích (`ref`) chưa được gắn kết (mount), các trình lắng nghe sẽ được thêm tự động ngay khi nó xuất hiện.
- `stop(): this` — Hủy kích hoạt lắng nghe và xóa tất cả các hàm xử lý khỏi phần tử hiện tại.
- `toggle(activity: boolean): this` — Bật hoặc tắt tính năng lắng nghe dựa trên giá trị được cung cấp.
- `reset(): this` — Khởi động lại quá trình lắng nghe. Nó được gọi tự động khi các tham số chính (loại sự kiện, tùy chọn, v.v.) thay đổi.

## Trạng thái & Truy xuất dữ liệu

Các phương thức để kiểm tra trạng thái hiện tại của đối tượng.

- `isActive(): boolean` — Trả về `true` nếu việc lắng nghe sự kiện hiện đang hoạt động.
- `getElement(): E | undefined` — Trả về phần tử DOM hoặc đối tượng hiện tại mà các trình lắng nghe được thiết lập.

## Cấu hình (Setters)

Tất cả các phương thức trong nhóm này đều hỗ trợ chuỗi phương thức (chaining) và tự động cập nhật các trình lắng nghe đang hoạt động.

- `setElement(element: ElementOrString): this` — Thay đổi động phần tử đích. Khi được sử dụng trong `EventRef`, nó cũng hỗ trợ `ref` phản ứng.
- `setElementControl(element: ElementOrString): this` — Thiết lập một phần tử điều khiển. Nếu phần tử này bị xóa khỏi DOM, việc lắng nghe sự kiện trên phần tử chính sẽ tự động dừng lại (bảo vệ chống rò rỉ bộ nhớ).
- `setType(type: string | string[]): this` — Cập nhật các loại sự kiện được lắng nghe (ví dụ: thay đổi từ `click` thành `dblclick`).
- `setListener(listener: Function): this` — Thay đổi hàm xử lý sự kiện mà không cần khởi động lại toàn bộ chu kỳ.
- `setOptions(options: EventOptions): this` — Cập nhật các tùy chọn của trình lắng nghe (`capture`, `passive`, `once`).
- `setDetail(detail: object): this` — Cập nhật dữ liệu tùy chỉnh có sẵn bên trong trình xử lý.

## Hành động

- `dispatch(detail?: object): this` — Kích hoạt sự kiện trên phần tử đích bằng lập trình. Nếu dữ liệu được truyền trong `detail`, nó sẽ được ưu tiên hơn dữ liệu được thiết lập thông qua `setDetail`.

## Các sự kiện đặc biệt

`EventRef` (thông qua lớp cơ sở `EventItem`) cung cấp khả năng xử lý nâng cao cho một số loại sự kiện nhất định:

### `resize`
Không giống như sự kiện `resize` tiêu chuẩn chỉ hoạt động trên đối tượng `window`, ở đây nó sử dụng `ResizeObserver`. Điều này cho phép theo dõi các thay đổi kích thước cho bất kỳ phần tử DOM cụ thể nào.

### `scroll-sync`
Phiên bản tối ưu hóa của sự kiện cuộn. Nó sử dụng `requestAnimationFrame` để đồng bộ hóa việc gọi hàm xử lý với tốc độ làm mới màn hình, ngăn chặn hiện tượng "giật" trong các tính toán nặng trong quá trình cuộn.
