// throttleDirective.js
// 一些常用的自定义指令
import Vue from 'vue'
// 节流函数
Vue.directive('throttle', {
inserted: function(el, binding) {
let timeoutId
let lastExecutedTime = 0
const { value, arg, modifiers } = binding
const delay = modifiers.immediate ? +arg || 200 : +arg || 0
const execute = function() {
clearTimeout(timeoutId)
value();
lastExecutedTime = Date.now()
}
el.addEventListener('click', function() {
const currentTime = Date.now()
if (currentTime - lastExecutedTime >= delay) {
execute()
} else {
clearTimeout(timeoutId)
timeoutId = setTimeout(execute, delay)
}
})
}
})
// 外部点击
Vue.directive('out-click', {
bind: function(el, binding, vnode) {
el.clickOutsideEvent = function(event) {
if (!(el === event.target || el.contains(event.target))) {
binding.value.call(this, event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unbind: function(el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
},
});
// 自动聚焦
Vue.directive('focus', {
inserted: function(el) {
el.focus();
},
});
// 图片懒加载
Vue.directive('lazy-img', {
inserted: function(el, binding) {
const img = new Image();
img.src = binding.value;
img.onload = () => {
el.src = binding.value;
};
},
});
// 防止重复点击
Vue.directive('noMoreClick', {
inserted(el, binding) {
el.addEventListener('click', () => {
el.style.pointerEvents = 'none'
setTimeout(() => {
el.style.pointerEvents = ''
}, 1000)
})
}
})
// 复制到粘贴板
Vue.directive('clipboard', {
bind(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
const clipboard = new Clipboard(el, {
text() { return binding.value },
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
})
clipboard.on('success', e => {
const callback = el._v_clipboard_success
callback && callback(e)
})
clipboard.on('error', e => {
const callback = el._v_clipboard_error
callback && callback(e)
})
el._v_clipboard = clipboard
}
},
unbind(el, binding) {
if (binding.arg === 'success') {
delete el._v_clipboard_success
} else if (binding.arg === 'error') {
delete el._v_clipboard_error
} else {
el._v_clipboard.destroy()
delete el._v_clipboard
}
}
})
// 滚动加载
Vue.directive('scroll-load', {
inserted(el, binding) {
const loadFunction = binding.value;
const scrollWrapper = el;
scrollWrapper.addEventListener('scroll', function () {
const scrollTop = scrollWrapper.scrollTop;
const scrollHeight = scrollWrapper.scrollHeight;
const clientHeight = scrollWrapper.clientHeight;
if (scrollTop + clientHeight >= scrollHeight * 0.95) {
loadFunction();
}
});
}
});
// 动态元素高度
Vue.directive('auto-height', {
componentUpdated(el, binding) {
const resize = () => {
el.style.height = 'auto';
el.style.height = el.scrollHeight + 'px';
};
el.addEventListener('input', resize);
resize(); // 初始化时调整一次
}
});
// 自定义长按事件:
Vue.directive('long-press', {
bind(el, binding) {
const pressTime = binding.arg;
const pressHandler = binding.value;
let pressTimer = null;
const startHandler = () => {
clearTimeout(pressTimer);
pressTimer = setTimeout(() => {
pressHandler();
}, pressTime);
};
const stopHandler = () => {
clearTimeout(pressTimer);
};
el.addEventListener('mousedown', startHandler);
el.addEventListener('mouseup', stopHandler);
el.addEventListener('mouseleave', stopHandler);
},
unbind(el) {
el.removeEventListener('mousedown', startHandler);
el.removeEventListener('mouseup', stopHandler);
el.removeEventListener('mouseleave', stopHandler);
}
});
// 限制输入框智能输入数字
Vue.directive('number-only', {
bind(el) {
function handleInput(event) {
// 处理输入事件
// 获取输入框的值
const inputValue = event.target.value;
// 将非数字字符替换为空字符串,得到格式化后的值
const formattedValue = inputValue.replace(/[^\d]/g, '');
// 如果原始值和格式化后的值不相等
// 将输入框的值设置为格式化后的值
if (inputValue !== formattedValue) {
event.target.value = formattedValue;
// 阻止默认行为
event.preventDefault();
}
}
el.addEventListener('input', handleInput);
el.$_number_only_destroy = () => {
el.removeEventListener('input', handleInput);
};
},
unbind(el) {
el.$_number_only_destroy();
}
});
// 触摸滑动处理
Vue.directive('touch-swipe', {
bind(el, binding) {
let startX, startY, startTime;
const handler = binding.value;
const touchEvent = e => {
const touch = e.touches[0];
switch (e.type) {
case 'touchstart':
startX = touch.clientX;
startY = touch.clientY;
startTime = new Date().getTime();
break;
case 'touchend':
const deltaX = touch.clientX - startX;
const deltaY = touch.clientY - startY;
const totalTime = new Date().getTime() - startTime;
if (Math.abs(deltaX) > 30 && totalTime < 1000) {
handler(deltaX > 0 ? 'right' : 'left');
}
if (Math.abs(deltaY) > 30 && totalTime < 1000) {
handler(deltaY > 0 ? 'down' : 'up');
}
break;
}
};
el.addEventListener('touchstart', touchEvent);
el.addEventListener('touchend', touchEvent);
el.$_touch_swipe_destroy = () => {
el.removeEventListener('touchstart', touchEvent);
el.removeEventListener('touchend', touchEvent);
};
},
unbind(el) {
el.$_touch_swipe_destroy();
}
});
// 元素拖拽
Vue.directive('draggable', {
bind(el) {
let startX, startY, initialX, initialY;
let isDragging = false;
function handleMouseDown(event) {
startX = event.clientX;
startY = event.clientY;
initialX = parseFloat(el.style.left) || 0;
initialY = parseFloat(el.style.top) || 0;
isDragging = true;
}
function handleMouseMove(event) {
// 处理鼠标移动事件
// 如果不处于拖拽状态,则直接返回
if (!isDragging) return;
// 计算鼠标移动的差值
const deltaX = event.clientX - startX;
const deltaY = event.clientY - startY;
// 根据差值计算新的位置
const newX = initialX + deltaX;
const newY = initialY + deltaY;
// 设置元素的新位置
el.style.left = newX + 'px';
el.style.top = newY + 'px';
}
function handleMouseUp() {
isDragging = false;
}
el.addEventListener('mousedown', handleMouseDown);
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
el.$_draggable_destroy = () => {
el.removeEventListener('mousedown', handleMouseDown);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
},
unbind(el) {
el.$_draggable_destroy();
}
});
// 自定义点击外部元素关闭模态的指令
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
if (!(el === event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unbind: function (el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
}
});
// 图片懒加载
Vue.directive('lazy', {
bind(el, binding) {
const img = new Image();
const color = Math.floor(Math.random() * 1000000);
img.src = binding.value;
el.style.backgroundColor = '#' + color;
img.onload = function () {
el.style.backgroundImage = 'url(' + binding.value + ')';
}
}
});
// 鼠标悬停变色
Vue.directive('hovercolor', {
bind(el, binding, vnode) {
el.onmouseover = function() {
el.style.color = binding.value; // 使用绑定的值作为颜色
}
el.onmouseout = function() {
el.style.color = ''; // 鼠标移出后颜色恢复
}
}
});
// 文字提示
Vue.directive('tooltip', {
bind(el, binding, vnode) {
var tooltip = document.createElement('div');
tooltip.style.position = 'absolute';
tooltip.style.bottom = '100%';
tooltip.style.left = '0';
tooltip.style.padding = '5px 10px';
tooltip.style.backgroundColor = '#333';
tooltip.style.color = '#fff';
tooltip.style.borderRadius = '5px';
tooltip.style.marginBottom = '10px';
tooltip.style.opacity = '0';
tooltip.style.transition = '0.3s';
tooltip.innerHTML = binding.value;
el.onmouseover = function() {
tooltip.style.opacity = '1';
}
el.onmouseout = function() {
tooltip.style.opacity = '0';
}
el.appendChild(tooltip);
}
});
// 图片预先加载
Vue.directive('img-preload', {
bind(el, binding, vnode) {
var img = new Image();
// 首先设置占位图
el.src = 'path/to/placeholder.jpg';
img.onload = function() {
// 实际图片加载完成后替换
el.src = binding.value;
}
// 开始加载实际图片
img.src = binding.value;
}
});
vue2常用自定义指令封装
最新推荐文章于 2025-02-27 23:05:40 发布