chore: consolidate new foundation and archive v1 (#1495)
This commit is contained in:
+208
@@ -0,0 +1,208 @@
|
||||
---
|
||||
title: Use withModifiers for Event Modifiers in Render Functions
|
||||
impact: MEDIUM
|
||||
impactDescription: Manual modifier implementation is error-prone; use withModifiers helper
|
||||
type: best-practice
|
||||
tags: [vue3, render-function, events, modifiers]
|
||||
---
|
||||
|
||||
# Use withModifiers for Event Modifiers in Render Functions
|
||||
|
||||
**Impact: MEDIUM** - When using render functions, event modifiers like `.stop`, `.prevent`, or `.self` require special handling. Use Vue's `withModifiers` helper function instead of manually implementing modifier logic, which is error-prone.
|
||||
|
||||
In templates, you can use modifiers like `@click.stop.prevent`. In render functions, you must either use camelCase concatenation for simple modifiers or the `withModifiers` helper for more complex ones.
|
||||
|
||||
## Task Checklist
|
||||
|
||||
- [ ] Use camelCase concatenation for capture, once, and passive modifiers
|
||||
- [ ] Use `withModifiers()` helper for stop, prevent, self, and key modifiers
|
||||
- [ ] Import `withModifiers` from 'vue' when needed
|
||||
- [ ] Combine multiple modifiers by passing them as an array
|
||||
|
||||
**Incorrect:**
|
||||
|
||||
```javascript
|
||||
import { h } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleClick = (e) => {
|
||||
// WRONG: Manual modifier implementation is error-prone
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
// ... actual handler logic
|
||||
};
|
||||
|
||||
return () => h('button', { onClick: handleClick }, 'Click');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
```javascript
|
||||
// WRONG: Forgetting to handle modifier in complex scenarios
|
||||
const handleDivClick = (e) => {
|
||||
// Intended: only trigger when clicking div itself, not children
|
||||
// This manual check is easy to get wrong
|
||||
if (e.target !== e.currentTarget) return;
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Correct:**
|
||||
|
||||
```javascript
|
||||
import { h, withModifiers } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleClick = () => {
|
||||
console.log('clicked!');
|
||||
};
|
||||
|
||||
return () =>
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
// CORRECT: Use withModifiers for stop and prevent
|
||||
onClick: withModifiers(handleClick, ['stop', 'prevent']),
|
||||
},
|
||||
'Click',
|
||||
);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## CamelCase Modifiers (No Helper Needed)
|
||||
|
||||
For `capture`, `once`, and `passive` modifiers, use camelCase concatenation:
|
||||
|
||||
```javascript
|
||||
import { h } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handler = () => console.log('event!');
|
||||
|
||||
return () =>
|
||||
h('div', {
|
||||
// @click.capture -> onClickCapture
|
||||
onClickCapture: handler,
|
||||
|
||||
// @keyup.once -> onKeyupOnce
|
||||
onKeyupOnce: handler,
|
||||
|
||||
// @scroll.passive -> onScrollPassive
|
||||
onScrollPassive: handler,
|
||||
|
||||
// @mouseover.once.capture -> onMouseoverOnceCapture
|
||||
onMouseoverOnceCapture: handler,
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## withModifiers Examples
|
||||
|
||||
```javascript
|
||||
import { h, withModifiers } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleClick = () => console.log('clicked');
|
||||
const handleSubmit = () => console.log('submitted');
|
||||
|
||||
return () =>
|
||||
h('div', [
|
||||
// .stop modifier
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
onClick: withModifiers(handleClick, ['stop']),
|
||||
},
|
||||
'Stop Propagation',
|
||||
),
|
||||
|
||||
// .prevent modifier
|
||||
h(
|
||||
'form',
|
||||
{
|
||||
onSubmit: withModifiers(handleSubmit, ['prevent']),
|
||||
},
|
||||
[h('button', { type: 'submit' }, 'Submit')],
|
||||
),
|
||||
|
||||
// .self modifier - only trigger if event.target is the element itself
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
onClick: withModifiers(handleClick, ['self']),
|
||||
style: { padding: '20px', background: '#eee' },
|
||||
},
|
||||
[h('button', "Click me (won't trigger parent)")],
|
||||
),
|
||||
|
||||
// Multiple modifiers
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: '/path',
|
||||
onClick: withModifiers(handleClick, ['stop', 'prevent']),
|
||||
},
|
||||
'Link',
|
||||
),
|
||||
]);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Key Modifiers
|
||||
|
||||
For keyboard events, use `withKeys` for key modifiers:
|
||||
|
||||
```javascript
|
||||
import { h, withKeys } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleEnter = () => console.log('Enter pressed');
|
||||
const handleEscape = () => console.log('Escape pressed');
|
||||
|
||||
return () =>
|
||||
h('input', {
|
||||
// @keyup.enter
|
||||
onKeyup: withKeys(handleEnter, ['enter']),
|
||||
|
||||
// Multiple keys
|
||||
onKeydown: withKeys(handleEscape, ['escape', 'esc']),
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## JSX Equivalent
|
||||
|
||||
```jsx
|
||||
import { withModifiers, withKeys } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const handleClick = () => console.log('clicked');
|
||||
|
||||
return () => (
|
||||
<div>
|
||||
<button onClick={withModifiers(handleClick, ['stop'])}>Stop</button>
|
||||
|
||||
<div onClick={withModifiers(handleClick, ['self'])}>
|
||||
<span>Child content</span>
|
||||
</div>
|
||||
|
||||
<input onKeyup={withKeys(() => {}, ['enter'])} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
- [Vue.js Render Functions - Event Modifiers](https://vuejs.org/guide/extras/render-function.html#event-modifiers)
|
||||
Reference in New Issue
Block a user