js中常晤面试难点,编写1个长按指令

用 Vue 编写三个长按指令

2018/08/22 · JavaScript
· Vue

原稿出处: Obaseki
Nosa   译文出处:kingrychen   

澳门葡京 1

有没有想过只需按住二个按钮几分钟就能在你的 Vue 应用中触发三个效应?

有没有想过创造四个按钮,按下三遍就足以解决单次输入(或然持续按住能够撤除全体输入)?

js中常晤面试难点,编写1个长按指令。想过?太好了,英豪所见略同。

本文正是教学怎么样在按下(大概按住)三个按钮时,既履行贰个函数,又清除输入。

先是,作者会讲解如何运用纯 JS 实现。而后也会创立1个 Vue 指令。

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

初稿参考

① 、定时器:①职务函数:函数结尾判断临界值;②运营定时器:a、周期性:timer=setInterval(职分函数,interval);b、壹遍性:timer=setTimeout(任务函数,wait);③悬停定时器:a、周期性:clearInterval(timer);timer=null;b、贰次性:clearTimeout(timer);timer=null;

一 、定时器:①职分函数:函数结尾判断临界值;②初阶定时器:a、周期性:timer=setInterval(职责函数,interval);b、一遍性:timer=setTimeout(职责函数,wait);③停下定时器:a、周期性:clearInterval(timer);timer=null;b、2回性:clearTimeout(timer);timer=null;

原理

要落到实处长按,用户要求按下并按住按钮几分钟。

想透过代码模拟这一作用,我们要求在鼠标“点击”按下按钮时,运维3个计时器监听用户按下的时间长度,如若时间超越大家盼望的时间长度,就实施相应的函数。

相当简单!不过,我们须要精通用户何时按住按钮。

1.轩然大波代理
给父元素添加事件,利用事件冒泡原理,在依照e.target来获得子成分
<ul id=”parentBox”>
<li class=”item”>1</li>
<li class=”item”>2</li>
<li class=”item”>3</li>
</ul>
let parentBox = document.getElementById(‘parentBox’);
parentBox.addEventListener(‘click’,function(e){
if(e.target && e.target.nodeName === ‘LI’){
let item = e.target;
console.log(item);
}
})
2.在循环中央银行使闭包
var arr = [1,2,3,4,5];
for(var i=0; i<arr.length; i++){
setTimeout(function(){
console.log(i)
},1000)
}
出口结果为:5,5,5,5,5
想要让i输出0,1,2,3,4
办法一使用闭包
for(var i=0; i<arr.length; i++){
set提姆eout(function(j){// 那里将值传入
console.log(j)// 那里接受
}(i),一千)// 闭包的应用
}
方法二let关键字
for(let i=0; i<arr.length; i++){
setTimout(function(){
console.log(i)
},1000)
}
3.轮转页面和窗口调整时,触发事件。
大旨绪想利用setTimeout延迟功效,来处总管件。
// 参数一接受实践函数,参数二延迟时间
function debounce(fn,delay){
// 维护2个timer
let timer = null;
// 能访问timer的闭包
return function(){
// 通过this和arguments获取函数的功用域和变量
let context = this;
let args = arguments;
// 假设事件被调用,清除timer然后重新安装timer
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(context,args);
},delay);
}
澳门葡京 ,}

二 、动画:变量:DISTANCE,DURATION,STEPS,step,interval,timer,moved;函数:start():setInterval(moveStep,bind(this),interval);moveStep():对象活动step;

2、动画:变量:DISTANCE,DURATION,STEPS,step,interval,timer,moved;函数:start():setInterval(moveStep,bind(this),interval);moveStep():对象活动step;

什么样达成

当用户点击按钮时,在点击事件在此以前会接触别的五个事件: mousedown
mouseup

当用户按下按钮时触发 mousedown 事件,用户甩手按钮时调用 mouseup
事件。

咱俩必要做的是:

  1. mousedown 事件触发时,运转计时器。
  2. 一旦 mouseup 事件在预料的 2
    秒前被触发,就免去计时器,不要执行相应的函数。就当作1个惯常的点击事件。

即使计时器在大家预设的时刻内尚未被免去,即 mouseup
事件没有被触发——那么能够看清用户没有自由按钮。因而,能够判断为三次长按,能够进行关联的函数。

③ 、事件:用户手动触发,浏览器自动触发,成分状态改变;当事件产生时,浏览器自动调用事件处理函数;绑定事件处理函数:①在要素伊始标签中绑定,<button
onclick=“js语句(this)”></button>;button.onclick=function(){eval(“js语句(this)”)};单击按钮时,button.onclick();②js中为要素事件处理函数属性赋值:btn.onclick=function(){//this=>button;……};③选用API添加事件监听:a、添加:btn.add伊夫ntListener(“事件名”,函数对象);b、移除:btn.remove伊芙ntListener(“事件名”,函数对象);

叁 、事件:用户手动触发,浏览器自动触发,成分状态改变;当事件爆发时,浏览器自动调用事件处理函数;绑定事件处理函数:①在要素发轫标签中绑定,<button
onclick=“js语句(this)”></button>;button.onclick=function(){eval(“js语句(this)”)};单击按钮时,button.onclick();②js中为要素事件处理函数属性赋值:btn.onclick=function(){//this=>button;……};③利用API添加事件监听:a、添加:btn.add伊芙ntListener(“事件名”,函数对象);b、移除:btn.remove伊夫ntListener(“事件名”,函数对象);

实践

让我们深远代码,达成这一效果。

先是,大家亟须定义三件事,即:

  1. 一个 变量 用于存款和储蓄计时器。
  2. 一个 启动 功能函数,用于运维计时器。
  3. 一个 取消 功用函数,用于撤除计时器。

肆 、事件周期:①破获:从外围成分向内层成分每种记录绑定事件处理函数,暗中同意暂不触发任何事件;②指标触发:优先触发指标成分上绑定的事件处理函数;*(目的成分为实在点击的成分;);③冒泡:遵照捕获的次第由内层向外围逐层触发捕获的事件处理函数;修改事件触发顺序:btn.add伊芙ntListener(“事件名”,函数对象,capture);*(capture表示是不是在捕获阶段提前触发,取值true或false);

④ 、事件周期:①抓获:从外围成分向内层成分各个记录绑定事件处理函数,暗中同意暂不触发任何事件;②对象触发:优先触发目的成分上绑定的事件处理函数;*(目的成分为实在点击的因素;);③冒泡:依据捕获的逐条由内层向外围逐层触发捕获的事件处理函数;修改事件触发顺序:btn.add伊芙ntListener(“事件名”,函数对象,capture);*(capture表示是或不是在抓获阶段提前触发,取值true或false);

变量

本条变量重要用来保存 setTimeout 的值,以便当鼠标 mouseup
事件触发时大家能够撤废它。

let pressTimer = null;

1
let pressTimer = null;

小编们把变量值设置为 null
是为了在实践裁撤操作前,检查那一个变量的值判断当前是不是有三个正值周转的计时器。

伍 、事件目的:事件发生时,自动创制封装事件消息的指标event,作为事件处理函数的第三个参数自动传入;①拦截冒泡:e.stopPropagation();②施用冒泡:可削减事件监听指标,但须取得指标成分:target;*(因为事件监听易形成闭包难以释放;);③收回事件(阻止私下认可行为):e.preventDefault();

五 、事件目的:事件发生时,自动创制封装事件音信的靶子event,作为事件处理函数的首先个参数自动传入;①阻挠冒泡:e.stopPropagation();②利用冒泡:可收缩事件监听目的,但须取得指标成分:target;*(因为事件监听易变异闭包难以释放;);③注销事件(阻止暗许行为):e.preventDefault();

初阶函数

其一函数包罗三个
setTimeout,它是
JavaScript 中的三当中坚办法,允许在一定时刻之后执行1个函数。

注意,click
事件执行的经过中,会接触此外四个事件。不过大家必要运转计时器的是
mousedown 事件。就算只是点击事件,不要求运转计时器。

// 成立计时器 ( 1s之后执行函数 ) let start = (e) => { //
假设是点击事件,不运营计时器 if (e.type === ‘click’ && e.button !== 0) {
return; } // 在运转一个定时器此前确定保障没有正在周转的计时器 if (pressTimer
=== null) { press提姆er = 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)
    }
}

陆 、事件坐标:①参阅显示屏左上角:e.screenX,e.screenY;②参照文书档案展现区左上角:e.clientX或e.x,e.clientY或e.y;③参阅所在父成分的左上角:e.offsetX,e.offsetY;

⑥ 、事件坐标:①参阅荧屏左上角:e.screenX,e.screenY;②参照文书档案显示区左上角:e.clientX或e.x,e.clientY或e.y;③参考所在父成分的左上角:e.offsetX,e.offsetY;

注销函数

其一函数见名知意,用来撤消运转函数成立的 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 事件触发,那些函数就会被调用。

⑦ 、页面滚动事件:onscroll;获得页面滚动过的距离:document.body.scrollTop或document.documentElement.scrollTop;

⑦ 、页面滚动事件:onscroll;得到页面滚动过的离开:document.body.scrollTop或document.documentElement.scrollTop;

安装触发器

余下的就是将事件监听器添加到想要长按效率的按钮上。

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 (pressTimer === null) { press提姆er = setTimeout(() => { //
执行职分 !!! }, 一千) } } // 截止计时器 let cancel = (e) => { //
检查是否有正值运营的计时器 if ( pressTimer !== null ) {
clearTimeout(pressTimer); pressTimer = null; } } // 选取 id 为
longPressButton 的成分 let el =
document.getElementById(‘longPressButton’); // 添加事件监听器
el.add伊夫ntListener(“mousedown”, start); // 长按事件撤除,废除计时器
el.add伊芙ntListener(“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);

8、cookie:创建:document.cookie=“变量名=值;expires=”+date.toGMTString();

8、cookie:创建:document.cookie=“变量名=值;expires=”+date.toGMTString();

用 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(() => { // 执行任务 !!! }, 一千) } } // 撤销计时器 let
cancel = (e) => { // 检查是还是不是有正在运作的计时器 if ( press提姆er !==
null ) { clearTimeout(pressTimer); pressTimer = null; } } //
添加事件监听器 el.add伊芙ntListener(“mousedown”, start); // 撤消计时器
el.add伊夫ntListener(“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
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 =
setTimeout(() => { // 执行函数 handler(); }, 一千) } } // 停止计时器
let cancel = (e) => { // 检查是还是不是有正在运维的计时器 if ( pressTimer
!== null ) { clearTimeout(pressTimer); pressTimer = null; } } //
运维函数 const handler = (e) => { // 执行传递给指令的艺术
binding.value(e) } // 添加事件监听器 el.add伊芙ntListener(“mousedown”,
start); // 撤消计时器 el.add伊芙ntListener(“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(); }, 一千) } } // 打消计时器 let cancel = (e) =>
{ // 检查计时器是还是不是有值 if ( pressTimer !== null ) {
clearTimeout(pressTimer); pressTimer = null; } } // 运转函数 const
handler = (e) => { // 执行传递给指令的不二法门 binding.value(e) } //
添加事件监听器 el.add伊夫ntListener(“mousedown”, start);
el.add伊芙ntListener(“touchstart”, start); // 撤消计时器
el.add伊夫ntListener(“click”, cancel); el.add伊芙ntListener(“mouseout”,
cancel); el.add伊芙ntListener(“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 赞 收藏
评论

澳门葡京 2

It’s never too old to learn!

转载

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website