这里收集了一些实用的自定义指令示例,可以直接在项目中使用。实用自定义指令示例,包括自动聚焦、权限控制、懒加载、防抖等常用指令。
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
使用:
<input v-focus placeholder="自动聚焦">
Vue.directive('permission', {
bind(el, binding) {
const { value } = binding
const permissions = ['edit', 'delete', 'admin']
if (value && !permissions.includes(value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})
使用:
<button v-permission="'edit'">编辑</button>
<button v-permission="'admin'">管理员操作</button>
Vue.directive('lazy', {
bind(el, binding) {
el.setAttribute('data-src', binding.value)
el.src = 'placeholder.jpg'
},
inserted(el) {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const src = el.getAttribute('data-src')
if (src) {
el.src = src
el.removeAttribute('data-src')
}
observer.unobserve(el)
}
})
})
observer.observe(el)
el._observer = observer
},
unbind(el) {
if (el._observer) {
el._observer.disconnect()
}
}
})
使用:
<img v-lazy="imageUrl" alt="懒加载图片">
Vue.directive('debounce', {
bind(el, binding) {
const delay = parseInt(binding.arg) || 300
let timer = null
el._debounce = function(event) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
binding.value(event)
}, delay)
}
el.addEventListener('input', el._debounce)
},
unbind(el) {
el.removeEventListener('input', el._debounce)
}
})
使用:
<input v-debounce:500="search" placeholder="搜索...">
Vue.directive('throttle', {
bind(el, binding) {
const delay = parseInt(binding.arg) || 300
let lastTime = 0
el._throttle = function(event) {
const now = Date.now()
if (now - lastTime >= delay) {
binding.value(event)
lastTime = now
}
}
el.addEventListener('click', el._throttle)
},
unbind(el) {
el.removeEventListener('click', el._throttle)
}
})
使用:
<button v-throttle:1000="submit">提交</button>
Vue.directive('click-outside', {
bind(el, binding) {
el._clickOutside = function(event) {
if (!(el === event.target || el.contains(event.target))) {
binding.value(event)
}
}
document.addEventListener('click', el._clickOutside)
},
unbind(el) {
document.removeEventListener('click', el._clickOutside)
}
})
使用:
<template>
<div v-click-outside="closeDropdown" class="dropdown">
<button @click="isOpen = !isOpen">菜单</button>
<ul v-show="isOpen">
<li>选项一</li>
<li>选项二</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
isOpen: false
}
},
methods: {
closeDropdown() {
this.isOpen = false
}
}
}
</script>
Vue.directive('copy', {
bind(el, binding) {
el._copyValue = binding.value
el._copy = function() {
const text = el._copyValue || el.innerText
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
console.log('复制成功')
})
} else {
const textarea = document.createElement('textarea')
textarea.value = text
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
console.log('复制成功')
}
}
el.addEventListener('click', el._copy)
},
update(el, binding) {
el._copyValue = binding.value
},
unbind(el) {
el.removeEventListener('click', el._copy)
}
})
使用:
<button v-copy="textToCopy">复制文本</button>
<button v-copy>复制按钮内的文字</button>
Vue.directive('longpress', {
bind(el, binding) {
const delay = parseInt(binding.arg) || 500
let timer = null
el._start = function() {
timer = setTimeout(() => {
binding.value()
}, delay)
}
el._cancel = function() {
if (timer) {
clearTimeout(timer)
timer = null
}
}
el.addEventListener('mousedown', el._start)
el.addEventListener('mouseup', el._cancel)
el.addEventListener('mouseleave', el._cancel)
el.addEventListener('touchstart', el._start)
el.addEventListener('touchend', el._cancel)
},
unbind(el) {
el.removeEventListener('mousedown', el._start)
el.removeEventListener('mouseup', el._cancel)
el.removeEventListener('mouseleave', el._cancel)
el.removeEventListener('touchstart', el._start)
el.removeEventListener('touchend', el._cancel)
}
})
使用:
<button v-longpress="showMenu">长按显示菜单</button>
<button v-longpress:1000="delete">长按1秒删除</button>
Vue.directive('draggable', {
bind(el) {
el.style.cursor = 'move'
el.style.position = 'absolute'
let isDragging = false
let startX, startY, initialX, initialY
el._mousedown = function(e) {
isDragging = true
startX = e.clientX
startY = e.clientY
initialX = el.offsetLeft
initialY = el.offsetTop
document.addEventListener('mousemove', el._mousemove)
document.addEventListener('mouseup', el._mouseup)
}
el._mousemove = function(e) {
if (!isDragging) return
const dx = e.clientX - startX
const dy = e.clientY - startY
el.style.left = initialX + dx + 'px'
el.style.top = initialY + dy + 'px'
}
el._mouseup = function() {
isDragging = false
document.removeEventListener('mousemove', el._mousemove)
document.removeEventListener('mouseup', el._mouseup)
}
el.addEventListener('mousedown', el._mousedown)
},
unbind(el) {
el.removeEventListener('mousedown', el._mousedown)
}
})
使用:
<div v-draggable class="draggable-box">拖拽我</div>
Vue.directive('input', {
bind(el, binding) {
const type = binding.arg || 'text'
el._input = function() {
let value = el.value
switch (type) {
case 'number':
value = value.replace(/[^\d]/g, '')
break
case 'decimal':
value = value.replace(/[^\d.]/g, '')
break
case 'phone':
value = value.replace(/[^\d]/g, '').slice(0, 11)
break
}
el.value = value
el.dispatchEvent(new Event('input'))
}
el.addEventListener('input', el._input)
},
unbind(el) {
el.removeEventListener('input', el._input)
}
})
使用:
<input v-input:number placeholder="只能输入数字">
<input v-input:decimal placeholder="只能输入数字和小数点">
<input v-input:phone placeholder="手机号">
Vue.directive('tooltip', {
bind(el, binding) {
const tooltip = document.createElement('div')
tooltip.className = 'tooltip'
tooltip.textContent = binding.value
tooltip.style.cssText = `
position: absolute;
background: #333;
color: white;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
display: none;
`
document.body.appendChild(tooltip)
el._tooltip = tooltip
el._showTooltip = function(e) {
tooltip.style.display = 'block'
tooltip.style.left = e.pageX + 10 + 'px'
tooltip.style.top = e.pageY + 10 + 'px'
}
el._hideTooltip = function() {
tooltip.style.display = 'none'
}
el.addEventListener('mouseenter', el._showTooltip)
el.addEventListener('mousemove', el._showTooltip)
el.addEventListener('mouseleave', el._hideTooltip)
},
unbind(el) {
el.removeEventListener('mouseenter', el._showTooltip)
el.removeEventListener('mousemove', el._showTooltip)
el.removeEventListener('mouseleave', el._hideTooltip)
if (el._tooltip) {
el._tooltip.parentNode.removeChild(el._tooltip)
}
}
})
使用:
<button v-tooltip="提示文字">悬停查看提示</button>
这些指令示例涵盖了常见的使用场景,可以根据项目需求进行调整和扩展。