事件
组件向外通知变化时使用事件。宏组件里用 defineEmits() 得到 emit 函数。
ts
import { defineEmits, defineHtml } from "@elfui/core";
interface SearchBoxEmits {
change: [value: string];
clear: [];
}
const emit = defineEmits<SearchBoxEmits>(["change", "clear"]);
const onInput = (event: Event): void => {
const input = event.target as HTMLInputElement;
emit("change", input.value);
};
export const SearchBox = defineHtml(`
<input @input=${onInput} />
<button @click=${() => emit("clear")}>清空</button>
`);监听事件
父组件模板里监听自定义事件:
ts
const update = (event: CustomEvent<string>): void => {
keyword.set(event.detail);
};
export const Page = defineHtml(` <search-box @change=${update}></search-box> `);单参数事件的 detail 就是该参数。多参数事件会以数组形式放入 detail。
组件事件是标准 CustomEvent。bubbles、composed、cancelable 默认均为 false;只有事件确实需要参与 DOM 冒泡或穿过 Shadow DOM 边界时才开启:
ts
defineOptions({
emitOptions: {
events: {
submit: { bubbles: true, composed: true, cancelable: true },
},
},
});
const accepted = emit("submit", value);emit() 返回 dispatchEvent() 的布尔结果;可取消事件被宿主 preventDefault() 后返回 false。
类型与运行时事件名
有限键的 interface 和 type 都可以作为 defineEmits 泛型。同文件声明可以由编译器提取事件名;如果事件类型从另一个文件导入,应同时传入运行时事件名数组:
ts
import type { SearchBoxEmits } from "./types";
const emit = defineEmits<SearchBoxEmits>(["change", "clear"]);数组中的名称会受泛型键约束,写入不存在的事件会得到 TypeScript 错误。
什么时候用事件
事件适合表达“已经发生的事”,比如 change、submit、close。如果父组件需要直接控制值,用 v-model 更清晰。
