directix
v1.7.0
Published
A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
Downloads
1,401
Maintainers
Keywords
Readme
Directix
English | 中文文档
A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3.
Features
- 🎯 Comprehensive - 57 commonly used directives and 57 composables
- 🔄 Vue 2/3 Compatible - Single codebase supports both Vue 2 and Vue 3
- 📦 Tree-shakable - Import only what you need
- 🔒 TypeScript - Full TypeScript support with type definitions
- 🚀 SSR Friendly - Multiple directives support SSR out of the box
- 📦 Multiple Formats - ESM, CJS, and IIFE (CDN) formats available
- ⚡ Zero Dependencies - Lightweight with minimal bundle size
- 🎨 Composables - Every directive has a corresponding composable for Composition API
- 🔧 Utility Exports - Export
configurePermission,getPermissionConfigand other utilities for advanced usage
Online Demo
Try it online with StackBlitz or CodeSandbox:
| Demo | StackBlitz | CodeSandbox |
|------|------------|-------------|
| Vue 3 | |
|
| Vue 2 |
|
|
Playground
Try the interactive Playground to configure directives and generate code:
- 57+ Directives - Full coverage of all Directix directives
- Vue 2 & Vue 3 - Generate code for either version
- Composables - Generate composable API code
- TypeScript Ready - Full type definitions included
- Monaco Editor - Full-featured code editor with syntax highlighting
- Live Preview - See directive effects in real-time
Each directive documentation page also includes a code generator for quick code snippets.
Installation
# npm
npm install directix
# yarn
yarn add directix
# pnpm
pnpm add directixVue 2 Support
For Vue 2.0-2.6, you need to install @vue/composition-api:
npm install @vue/composition-apiVue 2.7+ has built-in Composition API support, so no additional dependencies are needed.
CDN
You can also use Directix via CDN:
<!-- Vue 3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/directix/dist/index.iife.min.js"></script>
<!-- Vue 2.7+ -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/directix/dist/index.iife.min.js"></script>The CDN build works seamlessly with both Vue 2 and Vue 3.
Requirements
- Vue 2.0+ or Vue 3.0+
- Node.js 12.20+ (for build tools)
- For Vue 2.0-2.6:
@vue/composition-apiis required
Quick Start
Global Registration
// Vue 3
import { createApp } from 'vue'
import Directix from 'directix'
const app = createApp(App)
app.use(Directix)
// Or register specific directives only
app.use(Directix, {
directives: ['click-outside', 'copy', 'debounce']
})// Vue 2
import Vue from 'vue'
import Directix from 'directix'
Vue.use(Directix)On-Demand Import
import { vClickOutside, vCopy, vDebounce } from 'directix'
// Vue 3
app.directive('click-outside', vClickOutside)
app.directive('copy', vCopy)
// Vue 2
Vue.directive('click-outside', vClickOutside)Using Composables
Every directive has a corresponding composable for use with the Composition API:
import { useClickOutside, useCopy, useDebounce } from 'directix'
// In setup() or <script setup>
const { copy, copied } = useCopy({ source: textRef })
const { isHovering, bind } = useHover({ onEnter: handleEnter })
const { run: debouncedSearch } = useDebounce({ handler: search, wait: 500 })See the Composables section below for all available composables.
Nuxt Integration
Directix provides a Nuxt module for seamless integration with Nuxt 3 applications.
Installation
The Nuxt module is included in the main package. Simply add it to your nuxt.config.ts:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['directix/nuxt'],
directix: {
// Enable/disable the module (default: true)
enabled: true,
// Only include specific directives (optional)
include: ['v-click-outside', 'v-copy', 'v-debounce'],
// Or exclude specific directives (optional)
exclude: ['v-ripple'],
// Default options for directives (optional)
directiveOptions: {
'v-permission': {
config: {
getPermissions: () => ['read', 'write']
}
}
},
// Auto-import composables (default: true)
autoImportComposables: true
}
})Usage in Nuxt
Directives are automatically registered and composables are auto-imported:
<template>
<div v-click-outside="handleClose">
<button v-copy="text">Copy</button>
</div>
</template>
<script setup>
// Composables are auto-imported, no need to import manually
const { copy, copied } = useCopy({ source: text })
const { isHovering } = useHover({ onEnter: handleEnter })
</script>SSR Compatibility
Directives that are not SSR-compatible will only run on the client side. The Nuxt module handles this automatically.
Available Directives
Event Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-click-outside | Detect clicks outside an element | ❌ |
| v-click-delay | Delay click execution to prevent double clicks | ✅ |
| v-debounce | Debounce event handlers | ✅ |
| v-throttle | Throttle event handlers | ✅ |
| v-long-press | Detect long press events | ❌ |
| v-hover | Hover state detection | ❌ |
| v-hotkey | Keyboard shortcut binding | ✅ |
| v-touch | Touch gesture detection (swipe, pinch, rotate) | ❌ |
| v-swipe | Swipe gesture detection with mouse support | ❌ |
Form Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-copy | Copy text to clipboard | ❌ |
| v-focus | Auto focus an element | ✅ |
| v-mask | Input masking | ❌ |
| v-trim | Trim input whitespace | ✅ |
| v-money | Currency format input | ❌ |
| v-number | Number format input | ❌ |
| v-ellipsis | Text ellipsis overflow | ✅ |
Format Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-uppercase | Convert text to uppercase | ✅ |
| v-lowercase | Convert text to lowercase | ✅ |
| v-capitalcase | Capitalize first letter | ✅ |
| v-truncate | Truncate text with ellipsis | ✅ |
Visibility Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-lazy | Lazy load images | ❌ |
| v-intersect | Detect element intersection | ❌ |
| v-visible | Control element visibility | ✅ |
| v-loading | Show loading overlay | ✅ |
Scroll Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-scroll | Scroll event handling | ❌ |
| v-infinite-scroll | Infinite scrolling | ❌ |
| v-sticky | Sticky positioning | ❌ |
| v-pull-refresh | Pull to refresh functionality | ❌ |
| v-virtual-list | Virtual list for large datasets | ❌ |
Security Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-permission | Permission-based element control | ✅ |
| v-sanitize | Sanitize HTML content | ✅ |
Effect Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-ripple | Material design ripple effect | ❌ |
| v-draggable | Make elements draggable | ❌ |
Observer Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-resize | Element resize observer | ❌ |
| v-mutation | DOM mutation observer | ❌ |
UI Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-tooltip | Tooltip component | ❌ |
| v-image-preview | Image preview with zoom | ❌ |
| v-countdown | Countdown timer display | ✅ |
| v-print | Print element content | ❌ |
| v-watermark | Watermark overlay | ✅ |
| v-skeleton | Skeleton loading placeholder | ✅ |
| v-progress | Progress bar animation | ❌ |
| v-counter | Animated number counter | ✅ |
Gesture Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-pan | Pan/drag gesture | ❌ |
| v-pinch | Pinch/zoom gesture | ❌ |
| v-rotate-gesture | Rotation gesture | ❌ |
Visual Effect Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-blur | Background blur overlay | ❌ |
| v-fade | Fade in/out transition | ✅ |
| v-parallax | Parallax scrolling effect | ❌ |
| v-lottie | Lottie animation player | ❌ |
| v-typewriter | Typewriter animation | ✅ |
| v-click-wave | Click wave effect | ❌ |
Data Directives
| Directive | Description | SSR |
|-----------|-------------|-----|
| v-export | Export data (CSV/JSON/HTML) | ❌ |
| v-highlight | Keyword highlighting | ✅ |
| v-emoji | Emoji input filter | ❌ |
| v-context-menu | Right-click context menu | ❌ |
| v-fullscreen | Fullscreen toggle | ❌ |
✅ = SSR compatible | ❌ = Not SSR compatible
Composables
Every directive has a corresponding composable function for use with the Composition API. All composables are exported from directix:
Event Composables
| Composable | Description |
|------------|-------------|
| useClickOutside | Detect clicks outside an element |
| useClickDelay | Delay click execution |
| useDebounce | Debounce function calls |
| useThrottle | Throttle function calls |
| useLongPress | Detect long press gestures |
| useHover | Track hover state |
| useHotkey | Handle keyboard shortcuts |
| useTouch | Detect touch gestures |
| useSwipe | Detect swipe gestures |
Form Composables
| Composable | Description |
|------------|-------------|
| useCopy | Copy text to clipboard |
| useFocus | Manage element focus |
| useMask | Input masking |
| useTrim | Trim input whitespace |
| useMoney | Currency formatting |
| useNumber | Number formatting |
| useEllipsis | Text ellipsis overflow |
Format Composables
| Composable | Description |
|------------|-------------|
| useUppercase | Transform to uppercase |
| useLowercase | Transform to lowercase |
| useCapitalcase | Capitalize text |
| useTruncate | Truncate text |
Visibility Composables
| Composable | Description |
|------------|-------------|
| useLazy | Lazy load images |
| useIntersect | Detect element intersection |
| useVisible | Control element visibility |
| useLoading | Show loading overlay |
Scroll Composables
| Composable | Description |
|------------|-------------|
| useScroll | Track scroll position |
| useInfiniteScroll | Infinite scrolling |
| useSticky | Sticky positioning |
| usePullRefresh | Pull to refresh |
| useVirtualList | Virtual list for large datasets |
Other Composables
| Composable | Description |
|------------|-------------|
| usePermission | Permission checking |
| useSanitize | Sanitize HTML content |
| useRipple | Material design ripple effect |
| useDraggable | Make elements draggable |
| useResize | Element resize observer |
| useMutation | DOM mutation observer |
| useTooltip | Tooltip control |
| useImagePreview | Image preview with zoom |
| useCountdown | Countdown timer |
| usePrint | Print content |
| useWatermark | Watermark overlay |
| useSkeleton | Skeleton loading state |
| useProgress | Progress bar control |
| useCounter | Animated number counter |
| usePan | Pan gesture detection |
| usePinch | Pinch gesture detection |
| useRotateGesture | Rotation gesture detection |
| useBlur | Blur overlay control |
| useFade | Fade transition control |
| useParallax | Parallax scrolling |
| useLottie | Lottie animation control |
| useTypewriter | Typewriter effect |
| useExport | Data export utilities |
| useHighlight | Keyword highlighting |
| useEmoji | Emoji filtering |
| useContextMenu | Context menu control |
| useFullscreen | Fullscreen mode control |
| useClickWave | Click wave effect |
Composable Usage Example
<script setup>
import { ref } from 'vue'
import { useCopy, useHover, useDebounce } from 'directix'
// useCopy
const text = ref('Hello World')
const { copy, copied } = useCopy({ source: text })
// useHover
const buttonRef = ref()
const { isHovering, bind } = useHover({
onEnter: () => console.log('Entered'),
onLeave: () => console.log('Left')
})
// useDebounce
const { run: debouncedSearch } = useDebounce({
handler: (query) => fetchResults(query),
wait: 500
})
</script>
<template>
<button @click="copy()">
{{ copied ? 'Copied!' : 'Copy' }}
</button>
<button ref="buttonRef" :class="{ active: isHovering }">
Hover me
</button>
</template>Usage Examples
v-click-outside
Detect clicks outside an element, useful for closing dropdowns, modals, etc.
<template>
<div v-click-outside="closeDropdown">
<button @click="show = !show">Toggle</button>
<div v-if="show">Dropdown content</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useClickOutside } from 'directix'
const show = ref(false)
function closeDropdown() {
show.value = false
}
// Composable usage
const containerRef = ref()
useClickOutside(containerRef, () => {
show.value = false
})
</script>v-copy
Copy text to clipboard with a simple directive.
<template>
<!-- Simple usage -->
<button v-copy="textToCopy">Copy to clipboard</button>
<!-- With callbacks -->
<button v-copy="{ value: text, onSuccess: handleSuccess, onError: handleError }">
Copy with callback
</button>
</template>
<script setup>
import { ref } from 'vue'
import { useCopy } from 'directix'
const textToCopy = 'Hello, World!'
function handleSuccess(text) {
console.log('Copied:', text)
}
function handleError(error) {
console.error('Copy failed:', error)
}
// Composable usage
const sourceText = ref('Hello World')
const { copy, copied } = useCopy({ source: sourceText })
</script>v-debounce
Debounce event handlers to limit execution frequency.
<template>
<!-- Default: 300ms -->
<input v-debounce="handleInput" />
<!-- Custom wait time with modifier -->
<input v-debounce:500ms="handleInput" />
<!-- With options object -->
<input v-debounce="{ handler: handleInput, wait: 500, leading: true }" />
</template>
<script setup>
import { useDebounce } from 'directix'
function handleInput(event) {
console.log('Debounced input:', event.target.value)
}
// Composable usage
const { run: debouncedSearch, cancel } = useDebounce({
handler: (query) => fetchResults(query),
wait: 500
})
</script>v-throttle
Throttle event handlers to limit execution frequency.
<template>
<!-- Default: 300ms -->
<button v-throttle="handleClick">Throttled click</button>
<!-- Custom wait time with modifier -->
<button v-throttle:1s="handleClick">1 second throttle</button>
<!-- With options object -->
<button v-throttle="{ handler: handleClick, wait: 1000, leading: true, trailing: false }">
Throttle with options
</button>
</template>
<script setup>
import { useThrottle } from 'directix'
function handleClick() {
console.log('Throttled click')
}
// Composable usage
const { run: throttledScroll, cancel } = useThrottle({
handler: (position) => updatePosition(position),
wait: 100
})
</script>v-focus
Auto focus an element when mounted.
<template>
<!-- Simple usage -->
<input v-focus />
<!-- With options -->
<input v-focus="{ focus: true, refocus: true }" />
</template>
<script setup>
import { useFocus } from 'directix'
// Composable usage
const { focus, blur, hasFocus } = useFocus()
</script>v-permission
Control element visibility based on user permissions.
<template>
<!-- Simple permission check -->
<button v-permission="'admin'">Admin Only</button>
<!-- Multiple permissions (OR logic) -->
<button v-permission="['admin', 'editor']">Admin or Editor</button>
<!-- AND logic -->
<button v-permission="{ value: ['read', 'write'], mode: 'every' }">
Requires both permissions
</button>
<!-- Disable instead of remove -->
<button v-permission="{ value: 'admin', action: 'disable' }">
Disabled for non-admin
</button>
</template>
<script setup>
import { configurePermission, usePermission } from 'directix'
configurePermission({
getPermissions: () => ['read', 'write'],
getRoles: () => ['editor'],
roleMap: {
admin: ['*'],
editor: ['read', 'write', 'edit']
}
})
// Composable usage
const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()
const canEdit = hasPermission('edit')
</script>v-lazy
Lazy load images when they enter the viewport.
<template>
<!-- Simple usage -->
<img v-lazy="imageUrl" />
<!-- With placeholder and error image -->
<img v-lazy="{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }" />
</template>
<script setup>
import { useLazy } from 'directix'
// Composable usage
const { load, state, loaded } = useLazy({
src: 'image.jpg',
preload: 100
})
</script>v-mask
Input masking for formatted input.
<template>
<!-- Phone number -->
<input v-mask="'(###) ###-####'" placeholder="Phone" />
<!-- Date -->
<input v-mask="'##/##/####'" placeholder="MM/DD/YYYY" />
<!-- SSN -->
<input v-mask="{ mask: '###-##-####', placeholder: '_' }" placeholder="SSN" />
</template>
<script setup>
import { useMask } from 'directix'
// Composable usage
const { maskedValue, unmaskedValue, update } = useMask({
mask: '(###) ###-####',
value: '1234567890'
})
</script>v-loading
Show loading overlay on elements.
<template>
<!-- Simple usage -->
<div v-loading="isLoading">Content</div>
<!-- With options -->
<div v-loading="{ value: isLoading, text: 'Loading...', lock: true }">
Content with locked scroll
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useLoading } from 'directix'
const isLoading = ref(true)
// Composable usage
const { show, hide, setText } = useLoading({
text: 'Loading...',
lock: true
})
</script>v-sanitize
Sanitize HTML content to prevent XSS attacks.
<template>
<!-- Simple usage -->
<div v-sanitize="userContent"></div>
<!-- With custom allowed tags -->
<div v-sanitize="{ html: userContent, allowedTags: ['b', 'i', 'u'] }"></div>
</template>
<script setup>
import { useSanitize } from 'directix'
// Composable usage
const { sanitize, setAllowedTags } = useSanitize({
allowedTags: ['b', 'i', 'u', 'a']
})
const cleanHtml = sanitize(dirtyHtml)
</script>v-tooltip
Display tooltips on hover or click.
<template>
<!-- Simple usage -->
<button v-tooltip="'Tooltip content'">Hover me</button>
<!-- With options -->
<button v-tooltip="{ content: 'Tooltip', placement: 'bottom', trigger: 'click' }">
Click me
</button>
</template>
<script setup>
import { useTooltip } from 'directix'
// Composable usage
const { show, hide, updateContent, updatePosition } = useTooltip({
content: 'Tooltip content',
placement: 'top'
})
</script>v-image-preview
Preview images with zoom and gesture support.
<template>
<!-- Simple usage -->
<img v-image-preview src="thumbnail.jpg" data-preview="full.jpg" />
<!-- With options -->
<img v-image-preview="{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }" />
</template>
<script setup>
import { useImagePreview } from 'directix'
// Composable usage
const { open, close, zoom, rotate } = useImagePreview({
enablePinchZoom: true
})
</script>v-draggable
Make elements draggable.
<template>
<!-- Simple usage -->
<div v-draggable>Drag me</div>
<!-- With constraints -->
<div v-draggable="{ axis: 'x', bounds: 'parent' }">Horizontal drag only</div>
</template>
<script setup>
import { useDraggable } from 'directix'
// Composable usage
const { position, isDragging, reset } = useDraggable({
axis: 'x',
bounds: 'parent'
})
</script>v-uppercase / v-lowercase / v-capitalcase
Transform text case.
<template>
<input v-uppercase placeholder="Auto uppercase" />
<input v-lowercase placeholder="Auto lowercase" />
<input v-capitalcase placeholder="Capitalize first letter" />
</template>
<script setup>
import { useUppercase, useLowercase, useCapitalcase } from 'directix'
// Composable usage
const { transform: toUppercase } = useUppercase()
const { transform: toLowercase } = useLowercase()
const { transform: toCapitalcase } = useCapitalcase()
</script>v-truncate
Truncate text with ellipsis.
<template>
<!-- Simple usage -->
<p v-truncate="50">Long text here...</p>
<!-- With options -->
<p v-truncate="{ length: 100, suffix: '...', position: 'end' }">Long text...</p>
</template>
<script setup>
import { useTruncate } from 'directix'
// Composable usage
const { truncate } = useTruncate({ length: 100, suffix: '...' })
const shortText = truncate(longText)
</script>v-touch
Detect touch gestures.
<template>
<div v-touch="{ onSwipe: handleSwipe, onPinch: handlePinch }">
Swipe or pinch here
</div>
</template>
<script setup>
import { useTouch } from 'directix'
function handleSwipe(direction) {
console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
}
function handlePinch(scale) {
console.log('Pinched:', scale)
}
// Composable usage
const { onSwipe, onPinch, onRotate } = useTouch({
onSwipe: handleSwipe
})
</script>v-trim
Trim input whitespace.
<template>
<!-- Trim on blur (default) -->
<input v-trim />
<!-- Trim on input -->
<input v-trim="{ position: 'both', event: 'input' }" />
</template>
<script setup>
import { useTrim } from 'directix'
// Composable usage
const { trim, trimLeft, trimRight } = useTrim({ position: 'both' })
</script>v-money
Currency format input.
<template>
<input v-money="{ prefix: '$', precision: 2 }" placeholder="Enter amount" />
</template>
<script setup>
import { useMoney } from 'directix'
// Composable usage
const { format, parse } = useMoney({ prefix: '$', precision: 2 })
const formatted = format(1234.56) // "$1,234.56"
</script>v-number
Number format input.
<template>
<input v-number="{ precision: 2, min: 0, max: 100 }" placeholder="Enter number" />
</template>
<script setup>
import { useNumber } from 'directix'
// Composable usage
const { format, parse } = useNumber({ precision: 2, min: 0, max: 100 })
</script>v-click-delay
Delay click execution to prevent double clicks.
<template>
<!-- Default: 300ms delay -->
<button v-click-delay="handleClick">Click me</button>
<!-- Custom delay time -->
<button v-click-delay="{ handler: handleClick, delay: 500 }">500ms delay</button>
</template>
<script setup>
import { useClickDelay } from 'directix'
function handleClick() {
console.log('Clicked (delayed)')
}
// Composable usage
const { run: delayedClick, cancel } = useClickDelay({
handler: handleClick,
delay: 300
})
</script>v-countdown
Countdown timer display.
<template>
<!-- Simple usage -->
<span v-countdown="{ time: 60 }"></span>
<!-- With callbacks -->
<span v-countdown="{ time: 60, onTick: handleTick, onComplete: handleComplete }"></span>
<!-- Custom format -->
<span v-countdown="{ time: 3600, format: 'mm:ss' }"></span>
</template>
<script setup>
import { useCountdown } from 'directix'
function handleTick(remaining) {
console.log('Remaining:', remaining)
}
function handleComplete() {
console.log('Countdown complete!')
}
// Composable usage
const { start, pause, reset, remaining } = useCountdown({
time: 60,
onTick: handleTick,
onComplete: handleComplete
})
</script>v-ellipsis
Text ellipsis overflow with tooltip.
<template>
<!-- Simple usage -->
<div v-ellipsis style="width: 200px;">Long text that will be truncated</div>
<!-- With custom lines -->
<div v-ellipsis="{ lines: 2 }">Multi-line text with ellipsis</div>
</template>
<script setup>
import { useEllipsis } from 'directix'
// Composable usage
const { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })
</script>v-hotkey
Keyboard shortcut binding.
<template>
<!-- Simple usage -->
<div v-hotkey="{ 'ctrl+s': handleSave, 'ctrl+c': handleCopy }">
Press Ctrl+S to save
</div>
<!-- With modifiers -->
<input v-hotkey="{ 'enter': submit, 'escape': cancel }" />
</template>
<script setup>
import { useHotkey } from 'directix'
function handleSave() {
console.log('Saving...')
}
function handleCopy() {
console.log('Copying...')
}
// Composable usage
const { bind, unbind, unbindAll } = useHotkey({
'ctrl+s': handleSave
})
</script>v-print
Print element content.
<template>
<!-- Simple usage -->
<button v-print="printRef">Print</button>
<div ref="printRef">Content to print</div>
<!-- Print self -->
<div v-print="{ self: true }">Click to print this content</div>
</template>
<script setup>
import { ref } from 'vue'
import { usePrint } from 'directix'
const printRef = ref()
// Composable usage
const { print, printElement } = usePrint({
onBefore: () => console.log('Printing...'),
onComplete: () => console.log('Printed!')
})
</script>v-pull-refresh
Pull to refresh functionality.
<template>
<div v-pull-refresh="handleRefresh" style="height: 400px; overflow: auto;">
Pull down to refresh
</div>
<!-- With options -->
<div v-pull-refresh="{ handler: handleRefresh, threshold: 80, disabled: false }">
Content
</div>
</template>
<script setup>
import { usePullRefresh } from 'directix'
async function handleRefresh() {
// Fetch new data
await fetchData()
}
// Composable usage
const { isLoading, disable, enable } = usePullRefresh({
handler: handleRefresh
})
</script>v-swipe
Swipe gesture detection with mouse support.
<template>
<div v-swipe="handleSwipe" style="height: 200px;">
Swipe in any direction
</div>
<!-- With options -->
<div v-swipe="{ onSwipe: handleSwipe, threshold: 50, enableMouse: true }">
Swipe or drag with mouse
</div>
</template>
<script setup>
import { useSwipe } from 'directix'
function handleSwipe(direction) {
console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
}
// Composable usage
const { direction, lengthX, lengthY } = useSwipe({
onSwipe: handleSwipe,
threshold: 50
})
</script>v-virtual-list
Virtual list for rendering large datasets efficiently.
<template>
<div v-virtual-list="{ items: list, itemSize: 50 }" style="height: 500px;">
<template #default="{ item, index }">
<div :key="index">{{ item.name }}</div>
</template>
</div>
</template>
<script setup>
const list = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))
import { useVirtualList } from 'directix'
// Composable usage
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
largeList,
{ itemHeight: 50 }
)
</script>v-watermark
Watermark overlay.
<template>
<!-- Simple usage -->
<div v-watermark="'Confidential'" style="width: 100%; height: 400px;">
Protected content
</div>
<!-- With options -->
<div v-watermark="{ content: 'Draft', fontSize: 16, color: '#ccc', rotate: -20 }">
Content with watermark
</div>
</template>
<script setup>
import { useWatermark } from 'directix'
// Composable usage
const { show, hide, update } = useWatermark({
content: 'Confidential',
fontSize: 16,
color: '#ccc'
})
</script>v-blur
Background blur overlay effect.
<template>
<!-- Simple blur -->
<div v-blur="isBlurred">Content behind blur</div>
<!-- With radius -->
<div v-blur="15">Blur with 15px radius</div>
<!-- With options -->
<div v-blur="{
visible: isBlurred,
radius: 20,
overlayColor: 'rgba(255, 255, 255, 0.3)',
lockScroll: true
}">
Content
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useBlur } from 'directix'
const isBlurred = ref(false)
// Composable usage
const { show, hide, toggle } = useBlur({
radius: 10,
overlayColor: 'rgba(0, 0, 0, 0.5)'
})
</script>v-fade
Fade in/out transition effect.
<template>
<!-- Toggle visibility with fade -->
<div v-fade="isVisible">Fade content</div>
<!-- Fade in only -->
<div v-fade="'in'">Fade in</div>
<!-- With options -->
<div v-fade="{
visible: isVisible,
duration: 500,
easing: 'ease-in-out',
onComplete: () => console.log('Fade complete')
}">
Content
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useFade } from 'directix'
const isVisible = ref(true)
// Composable usage
const { fadeIn, fadeOut, toggle } = useFade({
duration: 300,
easing: 'ease'
})
</script>v-parallax
Parallax scrolling effect.
<template>
<!-- Simple parallax -->
<div v-parallax>Parallax content</div>
<!-- With speed factor -->
<div v-parallax="0.3">Slower parallax</div>
<!-- With options -->
<div v-parallax="{
speed: 0.5,
reverse: true,
mobileBreakpoint: 768
}">
Reverse parallax, disabled on mobile
</div>
</template>
<script setup>
import { useParallax } from 'directix'
// Composable usage
const { offset, progress, enabled } = useParallax({
speed: 0.5,
reverse: false
})
</script>v-lottie
Lottie animation player.
<template>
<!-- With URL -->
<div v-lottie="'https://assets.example.com/animation.json'"></div>
<!-- With animation data -->
<div v-lottie="animationData"></div>
<!-- With options -->
<div v-lottie="{
animationData: animationData,
autoplay: true,
loop: true,
speed: 1.5,
onComplete: () => console.log('Done')
}"></div>
</template>
<script setup>
import animationData from './animation.json'
import { useLottie } from 'directix'
// Composable usage
const { play, pause, stop, setSpeed, setDirection } = useLottie({
animationData,
autoplay: true,
loop: true
})
</script>v-typewriter
Typewriter animation effect.
<template>
<!-- Simple usage -->
<span v-typewriter="'Hello, World!'"></span>
<!-- With options -->
<span v-typewriter="{
text: 'Typing animation',
speed: 100,
cursor: '_',
onComplete: () => console.log('Done!')
}"></span>
<!-- Loop mode -->
<span v-typewriter="{
text: 'Loop animation',
loop: true,
deleteDelay: 1000
}"></span>
</template>
<script setup>
import { useTypewriter } from 'directix'
// Composable usage
const { start, stop, pause, resume } = useTypewriter({
text: 'Hello World',
speed: 50,
loop: false
})
</script>v-export
Export data (CSV/JSON/HTML/TXT).
<template>
<button v-export="exportData">Export CSV</button>
<button v-export="{ data: tableData, format: 'json', filename: 'my-data' }">
Export JSON
</button>
<button v-export="{
data: tableData,
format: 'csv',
columns: ['name', 'email'],
headers: { name: 'Name', email: 'Email Address' }
}">
Export with custom columns
</button>
</template>
<script setup>
const tableData = [
{ name: 'John', email: '[email protected]', age: 30 },
{ name: 'Jane', email: '[email protected]', age: 25 }
]
import { useExport } from 'directix'
// Composable usage
const { exportCSV, exportJSON, exportHTML } = useExport()
</script>v-highlight
Keyword highlighting.
<template>
<p v-highlight="'important'">This is an important message.</p>
<p v-highlight="['Vue', 'React']">Vue and React are popular frameworks.</p>
<p v-highlight="{
keywords: 'highlight',
className: 'my-highlight',
style: 'background: yellow; color: black;',
caseSensitive: true
}">
This will highlight the word.
</p>
</template>
<script setup>
import { useHighlight } from 'directix'
// Composable usage
const { highlight, clear } = useHighlight({
keywords: ['important', 'key'],
className: 'highlight'
})
</script>v-emoji
Emoji input filter.
<template>
<!-- Strip all emojis -->
<input v-emoji type="text" />
<!-- Strip emojis with replacement -->
<input v-emoji="{ strip: true, replacement: '*' }" type="text" />
<!-- Allow specific emojis -->
<input v-emoji="{ allowList: ['😊', '👍'] }" type="text" />
<!-- Block specific emojis -->
<input v-emoji="{ blockList: ['🚫', '❌'] }" type="text" />
</template>
<script setup>
import { useEmoji } from 'directix'
// Composable usage
const { stripEmojis, containsEmoji } = useEmoji({
strip: true,
allowList: ['😊', '👍']
})
</script>v-context-menu
Right-click context menu.
<template>
<div v-context-menu="menuItems">Right click here</div>
<div v-context-menu="{ items: menuItems, width: 200 }">Custom width</div>
</template>
<script setup>
import { useContextMenu } from 'directix'
const menuItems = [
{ label: 'Copy', handler: () => console.log('Copy') },
{ label: 'Paste', handler: () => console.log('Paste') },
{ divider: true, label: '' },
{ label: 'Delete', handler: () => console.log('Delete') }
]
// Composable usage
const { show, hide, setItems } = useContextMenu({
items: menuItems
})
</script>v-fullscreen
Fullscreen toggle.
<template>
<div v-fullscreen>
Content to show in fullscreen
<button @click="$el.toggleFullscreen()">Toggle</button>
</div>
<div v-fullscreen="{ fullscreenClass: 'my-fullscreen' }">
Custom fullscreen class
</div>
</template>
<script setup>
import { useFullscreen } from 'directix'
// Composable usage
const { isFullscreen, enter, exit, toggle } = useFullscreen({
onEnter: () => console.log('Entered fullscreen'),
onExit: () => console.log('Exited fullscreen')
})
</script>v-skeleton
Skeleton loading placeholder.
<template>
<!-- Basic usage -->
<div v-skeleton="isLoading">Content here</div>
<!-- With options -->
<div v-skeleton="{ loading: isLoading, animation: 'pulse', width: 200, height: 20 }">
Content here
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useSkeleton } from 'directix'
const isLoading = ref(true)
// Composable usage
const { show, hide, update } = useSkeleton({
animation: 'wave',
color: '#e8e8e8'
})
</script>v-progress
Progress bar animation.
<template>
<div v-progress="50">Progress at 50%</div>
<div v-progress="{
value: progressValue,
color: '#42b883',
height: 8,
showText: true
}">
Content
</div>
<div v-progress="{ indeterminate: true }">
Loading...
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useProgress } from 'directix'
const progressValue = ref(50)
// Composable usage
const { setProgress, start, finish, fail } = useProgress({
color: '#42b883',
height: 4
})
</script>v-counter
Animated number counter.
<template>
<span v-counter="1000">0</span>
<span v-counter="{
value: 10000,
duration: 3000,
decimals: 2,
useGrouping: true
}">0</span>
<span v-counter="{
value: targetValue,
formatter: (v) => '$' + v.toFixed(2)
}">0</span>
</template>
<script setup>
import { ref } from 'vue'
import { useCounter } from 'directix'
const targetValue = ref(1000)
// Composable usage
const { start, pause, reset, update } = useCounter({
startValue: 0,
endValue: 1000,
duration: 2000,
formatter: (v) => `$${v.toFixed(2)}`
})
</script>v-click-wave
Click wave effect.
<template>
<button v-click-wave>Click me</button>
<button v-click-wave="'rgba(255, 255, 255, 0.3)'">Custom color</button>
<button v-click-wave="{ color: 'red', duration: 400 }">Custom options</button>
</template>
<script setup>
import { ref } from 'vue'
import { useClickWave } from 'directix'
// Composable usage
const buttonRef = ref(null)
const { bind, trigger } = useClickWave({
color: 'currentColor',
duration: 500
})
// Bind to element on mount
onMounted(() => bind(buttonRef.value))
</script>v-pan
Pan/drag gesture.
<template>
<div v-pan="handlePan">Swipe me</div>
<div v-pan="{
onPan: handlePan,
direction: 'horizontal',
threshold: 20
}">
Horizontal only
</div>
</template>
<script setup>
import { usePan } from 'directix'
function handlePan(e) {
console.log('Direction:', e.direction)
console.log('Distance:', e.distance)
}
// Composable usage
const { isPanning, deltaX, deltaY } = usePan({
onPan: handlePan,
direction: 'horizontal'
})
</script>v-pinch
Pinch/zoom gesture.
<template>
<div v-pinch="handlePinch">Pinch to zoom</div>
<div v-pinch="{
onPinch: handlePinch,
enableTransform: true,
minScale: 0.5,
maxScale: 3
}">
Pinch to scale
</div>
</template>
<script setup>
import { usePinch } from 'directix'
function handlePinch(e) {
console.log('Scale:', e.scale)
console.log('Center:', e.centerX, e.centerY)
}
// Composable usage
const { scale, isPinching } = usePinch({
onPinch: handlePinch,
minScale: 0.5,
maxScale: 3
})
</script>v-rotate-gesture
Rotation gesture.
<template>
<div v-rotate-gesture="handleRotate">Rotate with two fingers</div>
<div v-rotate-gesture="{
onRotate: handleRotate,
enableTransform: true
}">
Rotate with transform
</div>
</template>
<script setup>
import { useRotateGesture } from 'directix'
function handleRotate(e) {
console.log('Rotation:', e.rotation)
console.log('Angle:', e.angle)
}
// Composable usage
const { angle, isRotating } = useRotateGesture({
onRotate: handleRotate,
enableTransform: true
})
</script>API Reference
DirectiveInstallOptions
interface DirectiveInstallOptions {
/** Register specific directives only */
directives?: string[]
/** Register all directives (default: true) */
all?: boolean
/** Global configuration for directives */
config?: Record<string, any>
}Directive Options
Each directive accepts different options. See the documentation for detailed API.
Roadmap
v1.7.0 (2026-04-15) - Visual Configuration Tool ✅
- Online Playground - Live editing environment with Vue 2/3 support
- Visual Configurator - Interactive parameter configuration panel
- Code Generator - Generate Vue 2/3/Composable/Nuxt code snippets
- Configuration Presets - Quick-start templates for common use cases
- Monaco Editor - CDN-loaded code editor with syntax highlighting
- Live Preview - Real-time directive effect preview
v1.8.0 (Planned - 2026-04-22) - Quality & Ecosystem
- Test Coverage - 90%+ unit test coverage, E2E testing with Playwright
- Performance Optimization - Bundle size optimization, tree-shaking improvements
- VS Code Extension - Autocompletion, hover documentation, code snippets
- CLI Tool -
directix create,directix init,directix doctor,directix migrate
v1.9.0 (Planned - 2026-04-29) - Documentation & Community
- Interactive Documentation - Live editing with instant preview
- Real-world Examples - 10+ practical scenario examples
- i18n Support - English, Chinese, Japanese documentation
- Developer Experience - Improved error messages, DevTools integration
- Plugin System - Community extension support
v1.10.0 (Planned - 2026-05-06) - Vue 3 Optimization & Security
- Vue 3 Optimization Preview - Suspense, Teleport support
- Mobile Optimization - Touch gestures, PWA support
- Accessibility (A11y) - ARIA attributes, keyboard navigation
- Security Enhancements - XSS protection, CSP compatibility
v1.11.0 (Planned - 2026-05-13) - Stability & Enterprise
- Stability - Browser compatibility, edge case fixes
- Performance Limits - Bundle ≤ 25KB, memory optimization
- Enterprise Features - Permissions, audit logs, config center
- v2.0 Migration Prep - Migration tool, breaking changes warnings
v2.0.0 (Future)
- Vue 3 exclusive optimizations
- Web Components support
Browser Support
| Browser | Version | |---------|---------| | Chrome | Latest | | Firefox | Latest | | Safari | Latest | | Edge | Latest |
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT © 2024-present saqqdy
