963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
4.3 KiB
4.3 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | ||||
|---|---|---|---|---|---|---|---|---|
| Use withDirectives for Custom Directives in Render Functions | LOW | Custom directives require special handling with withDirectives helper | best-practice |
|
Use withDirectives for Custom Directives in Render Functions
Impact: LOW - To apply custom directives to vnodes in render functions, use the withDirectives helper. Attempting to apply directives through props or other means will not work.
The withDirectives function wraps a vnode and applies directives with their values, arguments, and modifiers.
Task Checklist
- Import
withDirectivesfrom 'vue' when using custom directives - Import or define the directive object
- Pass directive as array:
[directive, value, argument, modifiers] - Multiple directives can be applied at once
Incorrect:
import { h } from 'vue';
const vFocus = { mounted: (el) => el.focus() };
export default {
setup() {
return () => {
// WRONG: Directives don't work as props
return h('input', {
'v-focus': true, // This doesn't work
});
};
},
};
Correct:
import { h, withDirectives } from 'vue';
// Custom directive
const vFocus = {
mounted: (el) => el.focus(),
};
export default {
setup() {
return () => {
// CORRECT: Use withDirectives
return withDirectives(
h('input'),
[[vFocus]], // Array of directive tuples
);
};
},
};
Directive with Value, Argument, and Modifiers
The directive tuple format: [directive, value, argument, modifiers]
import { h, withDirectives, resolveDirective } from 'vue';
// Directive definition
// Usage in template: <div v-pin:top.animate="200">
const vPin = {
mounted(el, binding) {
console.log(binding.value); // 200
console.log(binding.arg); // 'top'
console.log(binding.modifiers); // { animate: true }
el.style.position = 'fixed';
el.style[binding.arg] = binding.value + 'px';
},
};
export default {
setup() {
return () =>
withDirectives(h('div', 'Pinned content'), [
// [directive, value, argument, modifiers]
[vPin, 200, 'top', { animate: true }],
]);
},
};
Multiple Directives
import { h, withDirectives } from 'vue';
const vFocus = { mounted: (el) => el.focus() };
const vTooltip = {
mounted(el, { value }) {
el.title = value;
},
};
export default {
setup() {
return () =>
withDirectives(h('input', { placeholder: 'Enter text' }), [
[vFocus],
[vTooltip, 'This is a tooltip'],
]);
},
};
Using Registered Directives
For globally or locally registered directives, use resolveDirective:
import { h, withDirectives, resolveDirective } from 'vue';
// Assuming v-focus and v-tooltip are registered globally
export default {
setup() {
return () => {
const focus = resolveDirective('focus');
const tooltip = resolveDirective('tooltip');
return withDirectives(h('input'), [[focus], [tooltip, 'Helpful tip']]);
};
},
};
Practical Example: Click Outside Directive
import { h, withDirectives, ref } from 'vue';
const vClickOutside = {
mounted(el, binding) {
el._clickOutside = (event) => {
if (!el.contains(event.target)) {
binding.value(event);
}
};
document.addEventListener('click', el._clickOutside);
},
unmounted(el) {
document.removeEventListener('click', el._clickOutside);
},
};
export default {
setup() {
const isOpen = ref(true);
const closeDropdown = () => {
isOpen.value = false;
};
return () =>
isOpen.value
? withDirectives(h('div', { class: 'dropdown' }, 'Dropdown content'), [
[vClickOutside, closeDropdown],
])
: null;
},
};
JSX with Directives
Directives in JSX also require withDirectives:
import { withDirectives } from 'vue';
const vFocus = { mounted: (el) => el.focus() };
export default {
setup() {
return () => withDirectives(<input placeholder="Search..." />, [[vFocus]]);
},
};