实现用户按下超过半秒钟就执行对应的操作
思路
- 定义一个变量存储计时器
- 在用户按下的一瞬间启动计时器,当按下的时间超过半秒就执行对应的操作
- 在用户松开的一瞬间取消计时器并将该变量置空,以便多次操作 伪代码如下:
let pressTimer: NodeJS.Timer | null = null;
// 创建计时器
const start = (e: Event) => {
if (e.type === "click") {
return;
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
// 执行对应功能
}, 500);
}
};
// 取消计时器
const cancel = () => {
if (pressTimer !== null) {
clearTimeout(pressTimer);
pressTimer = null;
}
};
el.addEventListener("mousedown", start);
el.addEventListener("touchstart", start);
el.addEventListener("click", cancel);
el.addEventListener("mouseout", cancel);
el.addEventListener("touchend", cancel);
el.addEventListener("touchcancel", cancel);
自定义指令
自定义指令需要用到钩子函数,我在长按指令中用到的是 bind 钩子函数,结果出现 bug ,获取到的永远是第一次长按的元素信息,改用 update 解决也符合需求。
钩子函数
- bind:只调用一次,指令第一次绑定到元素时调用。
- inserted:被绑定元素插入父节点时调用。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
钩子函数参数
- el:指令所绑定的元素,可以用来直接操作 DOM。
- binding:一个对象。 name:指令名,value:指令的绑定值
- vnode:编译生成的虚拟节点
伪代码如下:
import {DirectiveOptions} from "vue";
const directive: DirectiveOptions = {
update: function (el, binding, vNode) {
// 确保提供的表达式是函数
if (typeof binding.value !== "function") {
// 获取组件名称
const compName = vNode.context;
// 将警告传递给控制台
let warn = `[longpress:] provided expression '${binding.expression}' is not a function, but has to be `;
if (compName) {
warn += `Found in component '${compName}' `;
}
console.warn(warn);
}
const handler = (e: Event) => {
// 执行功能
binding.value(e);
};
}
};
export default directive;
附上所有代码:
// longpress.ts
import {DirectiveOptions} from "vue";
const directive: DirectiveOptions = {
update: function (el, binding, vNode) {
if (typeof binding.value !== "function") {
const compName = vNode.context;
let warn = `[longpress:] provided expression '${binding.expression}' is not a function, but has to be `;
if (compName) {
warn += `Found in component '${compName}' `;
}
console.warn(warn);
}
let pressTimer: NodeJS.Timer | null = null;
const handler = (e: Event) => {
binding.value(e);
};
const start = (e: Event) => {
if (e.type === "click") {
return;
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
handler(e);
}, 500);
}
};
const cancel = () => {
if (pressTimer !== null) {
clearTimeout(pressTimer);
pressTimer = null;
}
};
document.oncontextmenu = function (event) {
event.preventDefault();
return false;
};
el.addEventListener('contextmenu',function (e){
e.preventDefault()
},false)
el.addEventListener("mousedown", start);
el.addEventListener("touchstart", start);
el.addEventListener("click", cancel);
el.addEventListener("mouseout", cancel);
el.addEventListener("touchend", cancel);
el.addEventListener("touchcancel", cancel);
}
};
export default directive;
使用指令:
// Tag.vue
<template>
<div v-longpress="showTest">
test
</div>
</template>
<script lang="ts">
import Vue from "vue";
import {Component} from "vue-property-decorator";
import longpress from "@/lib/longpress";
@Component({
directives: {longpress}
})
export default class Tags extends Vue {
showTest() {}
</script>
参考文献:自定义指令