v-on / r-on
Rue TSX 实际源码
import { type FC, ref } from '@rue-js/rue';
const NativeCard: FC<{
title: string;
note?: string;
'v-on:click-native-once'?: string;
}> = props => {
return (
<button className="btn btn-outline h-auto min-h-0 flex-col items-start py-3 normal-case">
<span>{props.title}</span>
{props.note ? <span className="text-xs opacity-70">{props.note}</span> : null}
</button>
);
};
const Demo: FC = () => {
const count = ref(0);
const keyword = ref('Rue');
const stopCount = ref(0);
const enterCount = ref(0);
const selfCount = ref(0);
const metaExactCount = ref(0);
const lastEvent = ref('等待交互');
const updateLastEvent = (message: string) => {
lastEvent.value = message;
};
const onMethodPath = (event: Event) => {
count.value += 1;
updateLastEvent('v-on:click -> ' + event.type + ' #' + count.value);
};
const onManualCall = (label: string, event?: Event) => {
updateLastEvent(label + (event ? ' -> ' + event.type : ''));
};
const onInput = (event: Event) => {
keyword.value = (event.target as HTMLInputElement).value;
updateLastEvent('r-on:input -> ' + keyword.value);
};
const onStopPrevent = () => {
stopCount.value += 1;
updateLastEvent('v-on:click-stop-prevent -> #' + stopCount.value);
};
const onEnter = (event: KeyboardEvent) => {
enterCount.value += 1;
updateLastEvent('v-on:keyup-enter -> ' + event.key + ' #' + enterCount.value);
};
const onSelfOnly = () => {
selfCount.value += 1;
updateLastEvent('v-on:click-self -> #' + selfCount.value);
};
const onMetaExact = () => {
metaExactCount.value += 1;
updateLastEvent('v-on:click-meta-exact -> #' + metaExactCount.value);
};
return (
<div className="grid gap-4">
<button className="btn btn-primary" v-on:click="onMethodPath">
v-on:click
</button>
<button className="btn btn-secondary" v-on:click="onManualCall('method() 不自动注入 event')">
method()
</button>
<button className="btn btn-accent" v-on:click="onManualCall('method($event) 显式注入', $event)">
method($event)
</button>
<input className="input input-bordered" value={keyword.value} r-on:input="onInput($event)" />
<a className="link link-primary" href="#noop" v-on:click-stop-prevent="onStopPrevent">
v-on:click-stop-prevent
</a>
<input className="input input-bordered" placeholder="按 Enter" v-on:keyup-enter="onEnter" />
<input className="input input-bordered" placeholder="按回车 keyCode 13" v-on:keyup-13="onEnter" />
<div className="rounded-box border border-base-300 p-4" v-on:click-self="onSelfOnly">
<span>点击容器空白处触发 v-on:click-self</span>
<button className="btn btn-ghost btn-sm">子元素不会触发 self</button>
</div>
<button className="btn btn-info" v-on:click-meta-exact="onMetaExact">
v-on:click-meta-exact
</button>
<NativeCard
title="root"
note="native + once 示例"
v-on:click-native-once="onMethodPath"
/>
<div className="rounded-box border border-base-300 bg-base-200 p-3 font-mono text-sm">
{lastEvent.value}
</div>
</div>
);
};
export default Demo;原生 TSX 对照写法
import { type FC, ref } from '@rue-js/rue';
const Demo: FC = () => {
const count = ref(0);
const keyword = ref('Rue');
const onMethodPath = (event: MouseEvent) => {
count.value += 1;
console.log('onClick ->', event.type, count.value);
};
const onManualCall = (label: string, event?: Event) => {
console.log(label, event?.type);
};
const onInput = (event: Event) => {
keyword.value = (event.target as HTMLInputElement).value;
};
const onStopPrevent = (event: MouseEvent) => {
event.stopPropagation();
event.preventDefault();
console.log('manual stop + prevent');
};
const onEnter = (event: KeyboardEvent) => {
if (event.key !== 'Enter') return;
console.log('manual enter');
};
const onKeyCode13 = (event: KeyboardEvent & { keyCode?: number; which?: number }) => {
const keyCode = event.keyCode ?? event.which;
if (keyCode !== 13) return;
console.log('manual keyCode 13');
};
const onSelfOnly = (event: MouseEvent) => {
if (event.target !== event.currentTarget) return;
console.log('manual self');
};
const onMetaExact = (event: MouseEvent) => {
if (!event.metaKey) return;
if (event.ctrlKey || event.altKey || event.shiftKey) return;
console.log('manual meta exact');
};
return (
<div className="grid gap-4">
<button className="btn btn-primary" onClick={onMethodPath}>
onClick
</button>
<button className="btn btn-secondary" onClick={() => onManualCall('method() 不自动注入 event')}>
method()
</button>
<button className="btn btn-accent" onClick={event => onManualCall('method($event) 显式注入', event)}>
method($event)
</button>
<input className="input input-bordered" value={keyword.value} onInput={onInput} />
<a className="link link-primary" href="#noop" onClick={onStopPrevent}>
onClick + stopPropagation + preventDefault
</a>
<input className="input input-bordered" placeholder="按 Enter" onKeyUp={onEnter} />
<input className="input input-bordered" placeholder="按回车 keyCode 13" onKeyUp={onKeyCode13} />
<div className="rounded-box border border-base-300 p-4" onClick={onSelfOnly}>
<span>手写 currentTarget / target 判断</span>
<button className="btn btn-ghost btn-sm">子元素按钮</button>
</div>
<button className="btn btn-info" onClick={onMetaExact}>
手写 meta + exact 判断
</button>
{/* 组件根元素事件通常需要组件显式透传 onClick 或暴露 root 事件 prop */}
</div>
);
};
export default Demo;修饰符速查
import { type FC, ref } from '@rue-js/rue';
const NativeCard: FC<{
title: string;
'v-on:click-native-once'?: string;
}> = props => (
<button className="btn btn-outline">
{props.title}
</button>
);
const Demo: FC = () => {
const lastEvent = ref('等待交互');
const write = (name: string) => {
lastEvent.value = name;
};
const onStop = (event: MouseEvent) => write('stop: ' + event.type);
const onPrevent = (event: MouseEvent) => write('prevent: ' + event.type);
const onSelf = (event: MouseEvent) => write('self: ' + event.type);
const onOnce = (event: MouseEvent) => write('once: ' + event.type);
const onCapture = (event: MouseEvent) => write('capture: ' + event.type);
const onPassiveWheel = (event: WheelEvent) => write('passive wheel: ' + event.type);
const onCtrl = (event: MouseEvent) => write('ctrl: ' + event.type);
const onShift = (event: MouseEvent) => write('shift: ' + event.type);
const onAlt = (event: MouseEvent) => write('alt: ' + event.type);
const onMeta = (event: MouseEvent) => write('meta: ' + event.type);
const onMetaExact = (event: MouseEvent) => write('meta exact: ' + event.type);
const onMiddle = (event: MouseEvent) => write('middle: ' + event.type);
const onEnter = (event: KeyboardEvent) => write('enter: ' + event.key);
const onTab = (event: KeyboardEvent) => write('tab: ' + event.key);
const onDelete = (event: KeyboardEvent) => write('delete: ' + event.key);
const onEsc = (event: KeyboardEvent) => write('esc: ' + event.key);
const onSpace = (event: KeyboardEvent) => write('space: ' + event.key);
const onArrowUp = (event: KeyboardEvent) => write('up: ' + event.key);
const onArrowDown = (event: KeyboardEvent) => write('down: ' + event.key);
const onArrowLeft = (event: KeyboardEvent) => write('left: ' + event.key);
const onArrowRight = (event: KeyboardEvent) => write('right: ' + event.key);
const onKeyCode13 = (event: KeyboardEvent) => write('keyCode 13: ' + event.key);
const onNativeRootClick = (event: MouseEvent) => write('native once: ' + event.type);
return (
<section className="grid gap-4">
<button v-on:click-stop="onStop">stop</button>
<button v-on:click-prevent="onPrevent">prevent</button>
<div v-on:click-self="onSelf">
self
<button>child button</button>
</div>
<button v-on:click-once="onOnce">once</button>
<div v-on:click-capture="onCapture">capture</div>
<div v-on:wheel-passive="onPassiveWheel">passive wheel</div>
<button v-on:click-ctrl="onCtrl">ctrl</button>
<button v-on:click-shift="onShift">shift</button>
<button v-on:click-alt="onAlt">alt</button>
<button v-on:click-meta="onMeta">meta</button>
<button v-on:click-meta-exact="onMetaExact">meta exact</button>
<button v-on:click-middle="onMiddle">middle</button>
<input v-on:keyup-enter="onEnter" placeholder="Enter" />
<input v-on:keyup-tab="onTab" placeholder="Tab" />
<input v-on:keyup-delete="onDelete" placeholder="Delete" />
<input v-on:keyup-esc="onEsc" placeholder="Esc" />
<input v-on:keyup-space="onSpace" placeholder="Space" />
<input v-on:keyup-up="onArrowUp" placeholder="ArrowUp" />
<input v-on:keyup-down="onArrowDown" placeholder="ArrowDown" />
<input v-on:keyup-left="onArrowLeft" placeholder="ArrowLeft" />
<input v-on:keyup-right="onArrowRight" placeholder="ArrowRight" />
<input v-on:keyup-13="onKeyCode13" placeholder="keyCode 13" />
<NativeCard title="root native once" v-on:click-native-once="onNativeRootClick" />
<output>{lastEvent.value}</output>
</section>
);
};
export default Demo;