- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma binaryTargets for openssl 3.0 - nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal cron, http->https redirect - prisma: add origin_goods.delisted migration, sync missing schema (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz - api: CORS wildcard reflection, helmet CORP cross-origin, price backfill in persistProductDetail, categoryIcon ancestor fallback, mediaByColor per-color gallery in public goods detail - admin: /admin base path (vite + router) - import-data.mjs: udt_name casting, serial sequence advance fix
138 lines
4.3 KiB
Markdown
138 lines
4.3 KiB
Markdown
---
|
|
title: System Modifier Keys Must Be Held During keyup Events
|
|
impact: MEDIUM
|
|
impactDescription: Modifier keys (ctrl, alt, shift, meta) behave differently with keyup - they must be held when the key is released
|
|
type: gotcha
|
|
tags: [vue3, events, keyboard, modifiers, keyup, shortcuts]
|
|
---
|
|
|
|
# System Modifier Keys Must Be Held During keyup Events
|
|
|
|
**Impact: MEDIUM** - When using system modifier keys (`.ctrl`, `.alt`, `.shift`, `.meta`) with `keyup` events, the modifier must still be pressed when the other key is released. Releasing the modifier key first will not trigger the event, causing keyboard shortcuts to appear broken.
|
|
|
|
## Task Checklist
|
|
|
|
- [ ] Understand that `@keyup.ctrl` requires Ctrl to be held while releasing another key
|
|
- [ ] Consider using `keydown` instead of `keyup` for modifier key combinations
|
|
- [ ] Use `.exact` when you need precise modifier key control
|
|
- [ ] Test keyboard shortcuts with proper key release order
|
|
|
|
**Incorrect:**
|
|
```html
|
|
<!-- WRONG: Expecting this to fire when Ctrl is released -->
|
|
<template>
|
|
<input @keyup.ctrl="onCtrlRelease" />
|
|
<!-- This does NOT fire when you just release Ctrl! -->
|
|
<!-- It fires when you release ANY key while holding Ctrl -->
|
|
</template>
|
|
```
|
|
|
|
```html
|
|
<!-- WRONG: Misunderstanding keyup.ctrl behavior -->
|
|
<template>
|
|
<div @keyup.ctrl="handleShortcut">
|
|
<!-- User presses Ctrl+S, releases Ctrl first, then S -->
|
|
<!-- Event does NOT fire because Ctrl wasn't held during S release -->
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
**Correct:**
|
|
```html
|
|
<!-- CORRECT: User must hold Ctrl while releasing another key -->
|
|
<template>
|
|
<input @keyup.ctrl.s="saveDocument" />
|
|
<!-- User presses Ctrl+S, then releases S while holding Ctrl -->
|
|
<!-- Event fires correctly -->
|
|
</template>
|
|
|
|
<script setup>
|
|
function saveDocument(event) {
|
|
event.preventDefault()
|
|
// Save logic here
|
|
}
|
|
</script>
|
|
```
|
|
|
|
```html
|
|
<!-- CORRECT: Use keydown for more intuitive modifier behavior -->
|
|
<template>
|
|
<div @keydown.ctrl.s="saveDocument">
|
|
<!-- keydown fires immediately when both keys are pressed -->
|
|
<!-- More intuitive for keyboard shortcuts -->
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
```html
|
|
<!-- CORRECT: Use .exact for precise modifier control -->
|
|
<template>
|
|
<!-- Only fires when ONLY Ctrl is pressed (no Shift, Alt, etc.) -->
|
|
<button @click.ctrl.exact="onCtrlClick">Ctrl+Click Only</button>
|
|
|
|
<!-- Fires with no system modifiers at all -->
|
|
<button @click.exact="onPlainClick">Plain Click Only</button>
|
|
</template>
|
|
```
|
|
|
|
## How System Modifiers Work with keyup
|
|
|
|
```javascript
|
|
// Timeline of Ctrl+S keydown:
|
|
// 1. User presses Ctrl (keydown fires)
|
|
// 2. User presses S while holding Ctrl (keydown fires)
|
|
|
|
// Timeline of Ctrl+S keyup:
|
|
// 3. User releases S while holding Ctrl (keyup.ctrl.s fires!)
|
|
// 4. User releases Ctrl (keyup fires, but not keyup.ctrl.s)
|
|
|
|
// Common mistake:
|
|
// 3. User releases Ctrl first (nothing fires for our handler)
|
|
// 4. User releases S (keyup.s fires, but not keyup.ctrl.s)
|
|
```
|
|
|
|
## System Modifier Keys
|
|
|
|
```html
|
|
<!-- Available system modifiers -->
|
|
<input @keyup.ctrl="..." /> <!-- Ctrl key -->
|
|
<input @keyup.alt="..." /> <!-- Alt key (Option on Mac) -->
|
|
<input @keyup.shift="..." /> <!-- Shift key -->
|
|
<input @keyup.meta="..." /> <!-- Cmd on Mac, Windows key on PC -->
|
|
```
|
|
|
|
## The .exact Modifier
|
|
|
|
```html
|
|
<!-- Different .exact behaviors -->
|
|
|
|
<!-- Fires even if Shift/Alt are also pressed -->
|
|
<button @click.ctrl="onClick">Ctrl + any other modifiers</button>
|
|
|
|
<!-- Fires ONLY when Ctrl alone is pressed -->
|
|
<button @click.ctrl.exact="onClick">Ctrl only, no other modifiers</button>
|
|
|
|
<!-- Fires ONLY when no system modifiers are pressed -->
|
|
<button @click.exact="onClick">No modifiers allowed</button>
|
|
```
|
|
|
|
## Best Practice: Prefer keydown for Shortcuts
|
|
|
|
```html
|
|
<template>
|
|
<div
|
|
tabindex="0"
|
|
@keydown.ctrl.s.prevent="save"
|
|
@keydown.ctrl.z.prevent="undo"
|
|
@keydown.ctrl.shift.z.prevent="redo"
|
|
>
|
|
<!-- keydown is more reliable for keyboard shortcuts -->
|
|
<!-- Add .prevent to stop browser default (e.g., save dialog) -->
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## Reference
|
|
- [Vue.js Event Handling - Key Modifiers](https://vuejs.org/guide/essentials/event-handling.html#key-modifiers)
|
|
- [Vue.js Event Handling - System Modifier Keys](https://vuejs.org/guide/essentials/event-handling.html#system-modifier-keys)
|