--- title: Use Function Shorthand for Simple Directives impact: LOW impactDescription: Function shorthand reduces boilerplate for directives with identical mounted/updated behavior type: best-practice tags: [vue3, directives, shorthand, code-style] --- # Use Function Shorthand for Simple Directives **Impact: LOW** - It's common for a custom directive to have the same behavior for `mounted` and `updated`, with no need for other hooks. In such cases, you can define the directive as a function instead of an object, reducing boilerplate and improving readability. The function will be called for both `mounted` and `updated` lifecycle hooks. ## Task Checklist - [ ] Use function shorthand when mounted and updated behavior is identical - [ ] Use object syntax when you need beforeMount, beforeUpdate, or unmounted hooks - [ ] Use object syntax when mounted and updated have different logic **Verbose (when not needed):** ```javascript // VERBOSE: Full object when behavior is identical const vColor = { mounted(el, binding) { el.style.color = binding.value; }, updated(el, binding) { el.style.color = binding.value; // Same as mounted }, }; const vHighlight = { mounted(el, binding) { el.style.backgroundColor = binding.value || 'yellow'; }, updated(el, binding) { el.style.backgroundColor = binding.value || 'yellow'; // Duplicated }, }; // Global registration - verbose app.directive('pin', { mounted(el, binding) { el.style.position = 'fixed'; el.style.top = binding.value + 'px'; }, updated(el, binding) { el.style.position = 'fixed'; el.style.top = binding.value + 'px'; }, }); ``` **Concise (function shorthand):** ```javascript // CONCISE: Function shorthand const vColor = (el, binding) => { el.style.color = binding.value; }; const vHighlight = (el, binding) => { el.style.backgroundColor = binding.value || 'yellow'; }; // Global registration - concise app.directive('pin', (el, binding) => { el.style.position = 'fixed'; el.style.top = binding.value + 'px'; }); ``` ## With script setup ```vue ``` ## When to Use Object Syntax Use the full object syntax when: ### 1. You Need Cleanup (unmounted hook) ```javascript // Need object syntax for cleanup const vClickOutside = { mounted(el, binding) { el._handler = (e) => { if (!el.contains(e.target)) binding.value(e); }; document.addEventListener('click', el._handler); }, unmounted(el) { document.removeEventListener('click', el._handler); }, }; ``` ### 2. Different Logic for mounted vs updated ```javascript // Need object syntax for different behavior const vLazyLoad = { mounted(el, binding) { // Initial setup - create observer el._observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { el.src = binding.value; el._observer.disconnect(); } }); el._observer.observe(el); }, updated(el, binding, vnode, prevVnode) { // Only update if value actually changed if (binding.value !== binding.oldValue) { el.src = binding.value; } }, unmounted(el) { el._observer?.disconnect(); }, }; ``` ### 3. You Need beforeMount or beforeUpdate ```javascript // Need object syntax for early lifecycle hooks const vAnimate = { beforeMount(el) { el.style.opacity = '0'; }, mounted(el) { requestAnimationFrame(() => { el.style.transition = 'opacity 0.3s'; el.style.opacity = '1'; }); }, beforeUpdate(el) { el.style.opacity = '0.5'; }, updated(el) { el.style.opacity = '1'; }, }; ``` ## Object Literal Values with Function Shorthand Function shorthand works well with object literal values: ```javascript const vDemo = (el, binding) => { console.log(binding.value.color); // => "white" console.log(binding.value.text); // => "hello!" el.style.color = binding.value.color; el.textContent = binding.value.text; }; ``` ```vue ``` ## Reference - [Vue.js Custom Directives - Function Shorthand](https://vuejs.org/guide/reusability/custom-directives#function-shorthand)