用 Vue 编写三个长按指令

2018/08/22 · JavaScript
· Vue

原版的书文出处: Obaseki
Nosa   译文出处:kingrychen   

凯旋门074网址 1

有未有想过只需按住一个按键几分钟就能够在你的 Vue 应用中触发一个功力?

有未有想过创造一个按键,按下三回就足以防除单次输入(可能持续按住可以消灭全部输入)?

想过?太好了,英雄英雄所见略同。

本文正是教师如何在按下(可能按住)多少个开关时,既试行七个函数,又毁灭输入。

率先,小编会疏解如何采取纯 JS 实现。而后也会成立贰个 Vue 指令。

请系好安全带。好戏在后边呢。

启航函数

以此函数包括三个
setTimeout,它是
JavaScript 中的一个骨干方法,允许在一依期刻现在施行二个函数。

注意,click
事件实施的长河中,会触发别的七个事件。不过大家供给运营停车计时器的是
mousedown 事件。假使只是点击事件,不需要运营放大计时器。

// 创立计时器 ( 1s之后实施函数 ) let start = (e) => { //
如若是点击事件,不运营反应计时器 if (e.type === ‘click’ && e.button !== 0) {
return; } // 在开发银行贰个沙漏在此之前确定保证没有正在运转的机械漏刻 if (pressTimer
=== null) { pressTimer = setTimeout(() => { // 推行职分 !!! }, 1000)
} }

1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建计时器 ( 1s之后执行函数 )
let start = (e) => {
    // 如果是点击事件,不启动计时器
    if (e.type === ‘click’ && e.button !== 0) {
        return;
    }
    // 在启动一个定时器之前确保没有正在运行的计时器
    if (pressTimer === null) {
        pressTimer = setTimeout(() => {
            // 执行任务 !!!
        }, 1000)
    }
}

设置触发器

剩余的正是将事件监听器加多到想要长按效果与利益的按键上。

addEventListener(“mousedown”, start); addEventListener(“click”, cancel);

1
2
addEventListener("mousedown", start);
addEventListener("click", cancel);

以上代码合到一齐是如此:

// 定义变量 let pressTimer = null; // 创造定时器( 1秒后实施函数 ) let
start = (e) => { if (e.type === ‘click’ && e.button !== 0) { return;
} if (press提姆er === null) { pressTimer = setTimeout(() => { //
推行职务 !!! }, 1000) } } // 结束电火花计时器 let cancel = (e) => { //
检查是或不是有正在运行的电磁关照计时器 if ( pressTimer !== null ) {
clearTimeout(press提姆er); pressTimer = null; } } // 接纳 id 为
longPressButton 的因素 let el =
document.getElementById(‘longPressButton’); // 增添事件监听器
el.addEventListener(“mousedown”, start); // 长按事件撤废,撤除电火花计时器el.addEventListener(“click”, cancel); el.add伊夫ntListener(“mouseout”,
cancel);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 定义变量
let pressTimer = null;
 
// 创建计时器( 1秒后执行函数 )
let start = (e) => {
 
    if (e.type === ‘click’ && e.button !== 0) {
        return;
    }
 
    if (pressTimer === null) {
        pressTimer = setTimeout(() => {
 
            // 执行任务 !!!
 
        }, 1000)
    }
}
 
// 停止计时器
let cancel = (e) => {
 
    // 检查是否有正在运行的计时器
    if ( pressTimer !== null ) {
        clearTimeout(pressTimer);
        pressTimer = null;
    }
}
 
// 选择 id 为 longPressButton 的元素
let el = document.getElementById(‘longPressButton’);
 
// 添加事件监听器
el.addEventListener("mousedown", start);
 
// 长按事件取消,取消计时器
el.addEventListener("click", cancel);
el.addEventListener("mouseout", cancel);

撤除函数

凯旋门074网址,本条函数见名知意,用来撤废运维函数创造的 setTimeout

要取消 setTimeout ,能够接纳 JavaScript 中的
clearTimeout
方法,它根本用来废除
setTimeout()
方法设置的沙漏。

在使用 clearTimeout 在此之前,需求检查 pressTimer 变量是或不是为
null。若无为
null澳门凯旋门注册网址,,意味着有叁个正在运行的电火花计时器。由此,我们需求先去掉它,并且将
澳门凯旋门游戏网址,pressTimer 变量设置为 null

let cancel = (e) => { // 检查 pressTimer 的值是不是为 null if
(pressTimer !== null) { clearTimeout(pressTimer) pressTimer = null } }

1
2
3
4
5
6
7
let cancel = (e) => {
    // 检查 pressTimer 的值是否为 null
    if (pressTimer !== null) {
        clearTimeout(pressTimer)
        pressTimer = null
    }
}

一旦 mouseup 事件触发,这些函数就能够被调用。

怎么着贯彻

当顾客点击按键时,在点击事件在此以前会触发别的两个事件: mousedown   译文出处。 和
mouseup

当客户按下按键时触发 mousedown 事件,客商甩手开关时调用 mouseup
事件。

我们需求做的是:

  1. mousedown 事件触发时,运转放大计时器。
  2. 一旦 mouseup 事件在预料的 2
    秒前被触发,就扼杀放大计时器,不要执行相应的函数。就作为贰个管见所及的点击事件。

若是电火花计时器在大家预设的光阴内未有被破除,即 mouseup
事件未有被触发——那么可以剖断客商并没有自由按键。由此,能够判明为壹遍长按,能够施行关联的函数。

用 Vue 指令包装

创办 Vue 指令时,能够创立全局或一些指令,本文中,大家使用全局指令。

率先,我们必得评释自定义指令的名称。

Vue.directive(‘longpress’, { })

1
2
3
Vue.directive(‘longpress’, {
 
})

那就报了名了多少个名称叫 v-longpress 的全局自定义指令。

接下去,大家增添带参数的 bind
   译文出处。钩子函数,它同意大家援引指令绑定的因素,获取传递给指令的值,并标识指令使用的零部件。

Vue.directive(‘longpress’, { bind: function(el, binding, vNode) { } })

1
2
3
4
5
Vue.directive(‘longpress’, {
    bind: function(el, binding, vNode) {
 
    }
})

接下去,大家在 bind 函数中增加长按效果与利益的代码。

Vue.directive(‘longpress’, { bind: function(el, binding, vNode) { //
定义变量 let pressTimer = null; // 定义函数管理程序 // 创制电磁打点计时器(
1秒后实行函数 ) let start = (e) => { if (e.type === ‘click’ &&
e.button !== 0) { return; } if (pressTimer === null) { pressTimer =
setTimeout(() => { // 施行任务 !!! }, 1000) } } // 打消计时器 let
cancel = (e) => { // 检查是还是不是有正值运维的测量时间的装置 if ( press提姆er !==
null ) { clearTimeout(pressTimer); pressTimer = null; } } //
增添事件监听器 el.add伊芙ntListener(“mousedown”, start); // 打消计时器el.addEventListener(“click”, cancel); el.addEventListener(“mouseout”,
cancel); } })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Vue.directive(‘longpress’, {
    bind: function(el, binding, vNode) {
 
        // 定义变量
        let pressTimer = null;
 
        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {
 
            if (e.type === ‘click’ && e.button !== 0) {
                return;
            }
 
            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
 
                    // 执行任务 !!!
 
                }, 1000)
            }
        }
 
        // 取消计时器
        let cancel = (e) => {
 
            // 检查是否有正在运行的计时器
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }
 
        // 添加事件监听器
        el.addEventListener("mousedown", start);
 
        // 取消计时器
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
    }
})

接下去,大家必要丰盛叁个函数来运维传递给 longpress 指令的法门。

Vue.directive(‘longpress’, { bind: function(el, binding, vNode) { //
定义变量 let pressTimer = null; // 定义函数管理程序 // 创设计时器(
1秒后进行函数 ) let start = (e) => { if (e.type === ‘click’ &&
e.button !== 0) { return; } if (pressTimer === null) { pressTimer =
set提姆eout(() => { // 实行函数 handler(); }, 1000) } } // 甘休定时器let cancel = (e) => { // 检查是不是有正值运维的电磁打点计时器 if ( pressTimer
   译文出处。!== null ) { clearTimeout(pressTimer); pressTimer = null; } } //
运营函数 const handler = (e) => { // 实践传递给指令的措施
binding.value(e) } // 增加事件监听器 el.addEventListener(“mousedown”,
start); // 撤销计时器 el.addEventListener(“click”, cancel);
el.add伊夫ntListener(“mouseout”, cancel); } })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Vue.directive(‘longpress’, {
    bind: function(el, binding, vNode) {
 
        // 定义变量
        let pressTimer = null;
 
        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {
 
            if (e.type === ‘click’ && e.button !== 0) {
                return;
            }
 
            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // 执行函数
                    handler();
                }, 1000)
            }
        }
 
        // 停止计时器
        let cancel = (e) => {
 
            // 检查是否有正在运行的计时器
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }
 
        // 运行函数
        const handler = (e) => {
            // 执行传递给指令的方法
            binding.value(e)
        }
 
        // 添加事件监听器
        el.addEventListener("mousedown", start);
 
        // 取消计时器
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
    }
})

近日,能够在 Vue
应用中央银行使那些命令了,除非使用者给指令传入的值不是二个函数。因而,我们须要经过警示反馈给使用者。

为了反映给使用者,大家在 bind 函数中增添了以下内容:

// 确认保障提供的表明式是函数 if (typeof binding.value !== ‘function’) { //
获取组件名称 const compName = vNode.context.name; // 将警示传递给调节台
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); }

1
2
3
4
5
6
7
8
9
10
// 确保提供的表达式是函数
if (typeof binding.value !== ‘function’) {
    // 获取组件名称
    const compName = vNode.context.name;
    // 将警告传递给控制台
    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);
}

谈起底,假诺这一个命令也适用于触屏设备,那会是极好的。因而,我们增添了
touchstart、touchend

touchcancel
事件监听器。

终极代码如下:

Vue.directive(‘longpress’, { bind: function(el, binding, vNode) { //
确定保障提供的表达式是函数 if (typeof binding.value !== ‘function’) { //
获取组件名称 const compName = vNode.context.name; // 将警示传递给调整台
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 = null; // 定义函数管理程序 // 创设计时器( 1秒后实行函数 )
let start = (e) => { if (e.type === ‘click’ && e.button !== 0) {
return; } if (pressTimer === null) { pressTimer = setTimeout(() => {
// 实践函数 handler(); }, 1000) } } // 撤废电火花计时器 let cancel = (e) =>
{ // 检查停车计时器是不是有值 if ( pressTimer !== null ) {
clearTimeout(pressTimer); pressTimer = null; } } // 运营函数 const
handler = (e) => { // 实践传递给指令的秘籍 binding.value(e) } //
增添事件监听器 el.addEventListener(“mousedown”, start);
el.addEventListener(“touchstart”, start); // 打消反应计时器el.add伊夫ntListener(“click”, cancel); el.add伊夫ntListener(“mouseout”,
cancel); el.addEventListener(“touchend”, cancel);
el.add伊夫ntListener(“touchcancel”, cancel); } })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Vue.directive(‘longpress’, {
    bind: function(el, binding, vNode) {
 
        // 确保提供的表达式是函数
        if (typeof binding.value !== ‘function’) {
            // 获取组件名称
            const compName = vNode.context.name;
            // 将警告传递给控制台
            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 = null;
 
        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {
 
            if (e.type === ‘click’ && e.button !== 0) {
                return;
            }
 
            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // 执行函数
                    handler();
                }, 1000)
            }
        }
 
        // 取消计时器
        let cancel = (e) => {
 
            // 检查计时器是否有值
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }
 
        // 运行函数
        const handler = (e) => {
            // 执行传递给指令的方法
            binding.value(e)
        }
 
        // 添加事件监听器
        el.addEventListener("mousedown", start);
        el.addEventListener("touchstart", start);
 
        // 取消计时器
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
        el.addEventListener("touchend", cancel);
        el.addEventListener("touchcancel", cancel);
    }
})

于今得以在 Vue 组件里应用了:

<template> <div> <button v-longpress=”incrementPlusTen”
@click=”incrementPlusOne”>{{value}}</button> </div>
</template> <script> export default { data() { return {
value: 10 } }, methods: { // 增加1 incrementPlusOne() { this.value++ },
// 增加10 incrementPlusTen() { this.value += 10 } } } </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
    <div>
        <button v-longpress="incrementPlusTen" @click="incrementPlusOne">{{value}}</button>
    </div>
</template>
 
<script>
export default {
    data() {
        return {
            value: 10
        }
    },
    methods: {
        // 增加1
        incrementPlusOne() {
            this.value++
        },
        // 增加10
        incrementPlusTen() {
            this.value += 10
        }
    }
}
</script>

. . .

假如你想清楚越来越多关于 自定义指令、可用的
钩子函数、能够传递到这一个钩子函数中的 参数函数简写 的信息,
参照 @vuejs
官方文书档案,笔者做了很好的解释。

收工,干杯!

. . .

1 赞 收藏
评论

凯旋门074网址 2

原理

要贯彻长按,客户需求按下并按住按键几分钟。

想经过代码模拟那豆蔻年华功能,大家必要在鼠标“点击”按下开关时,运维叁个计时器监听顾客按下的时间长度,假诺时间超越我们意在的时间长度,就推行相应的函数。

很简单!然则,大家须求掌握客户哪天按住按键。

实践

让我们深深代码,达成那朝气蓬勃效率。

第后生可畏,大家必须要定义三件事,即:

  1. 一个 变量 用于存款和储蓄放大计时器。
  2. 一个 启动 作用函数,用于运营放大计时器。
  3. 一个 取消 作用函数,用于裁撤电火花计时器。

变量

这一个变量重要用以保存 setTimeout 的值,以便当鼠标 mouseup
事件触发时我们得以撤除它。

let pressTimer = null;

1
let pressTimer = null;

咱俩把变量值设置为 null
是为着在进行废除操作前,检查这么些变量的值判定当前是还是不是有多个正在运营的沙漏。

相关文章