================================惯例碎碎念前言================================

当时首先想到要做长按事件的时候,我想到的是vue内部的自定义指令,毕竟官网里边有这么一句描述:

有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令

但是项目用在app中,因为另一个未知原因的bug,自定义事件躺枪(至今死不瞑目)。长按事件被我改成了在初始化时,就直接绑定到需要他的dom上。

================================正经文================================

绑定的命令写在mounted钩子里,这是因为在created内部我也找不到dom,而在mounted阶段,所有的dom结构和数据都被展示到页面当中,

详情可以参见“vue生命周期强刷”:https://www.cnblogs.com/padding1015/p/9159381.html

所以,下边的代码经过不断的轮回,最终是写在mounted里边的

let oDiv = document.getElementById('canvas');

// 因为长按事件要加在div#canvas上的,如果事件是任何地方的话,就是document

 oDiv.addEventListener("touchstart", function(e) {}, false);

 oDiv.addEventListener("touchmove", function(e) {}, false);

 oDiv.addEventListener("touchend", function(e) {}, false);

至于,三个绑定事件的回调里再写什么,就不太关vue的事了(dui,就是这么草率)。

在公布最终的成型代码之前,容我先补一波关于事件的”兵”。

主要兵线呢有三条:

中路:dom2级事件处理程序

上路:事件流

下路:触摸事件

所需事件知识点分布如下图:

(查看大图:右键新标签中打开)掌握了上边的知识点后,就是在长按功能里边的应用了。

别急~

长按功能原理分析一波:

所谓的长按其实就是手指按下去,不移动,超过一定时间才把手指拿开的一个过程(我说的好有道理哈哈哈。然后听到一片同一个声音:废话!!)。

而在这个过程中,正好是触摸的三个事件。

监听手指按下去后是否有移动,就该touches上场了,监听他的clientX,clientY只要没变就是没移动。

并且在这个过程中,还会不时地有地方的英雄冒出来干扰我们补兵。那就是一个手机自带的效果了:

  长按时,在移动端触摸文字,(至少ios里)会出现选择文字等干扰我们的真正功能,用了preventDefault()这个属性后就没有了。

纸上谈兵是没用的额,直接上长按功能代码

为了不必要的麻烦(其实就是我懒得写),把多余的其他代码删掉了,所以不要惊讶export default里边为什么只有mounted。

<script>
let x = 0,
y = 0,
z = 0,
timer1 = null;
export default {
mounted(){
let oDiv = document.getElementById('canvas');
oDiv.addEventListener("touchstart", function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
if (e.touches.length > 1) {
return false;
}
z = 0;
timer1 = setTimeout(function() {
z = 1;
}, 500);
x = e.touches[0].clientX;
y = e.touches[0].clientY;
}, false);
oDiv.addEventListener("touchmove", function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
if (x != e.touches[0].clientX || y != e.touches[0].clientY) {
clearTimeout(timer1);
return false;
}
}, false);
oDiv.addEventListener("touchend", function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
if (z != 1) {
clearTimeout(timer1);
x = 0;
y = 0;
return false;
} else if(z=1){
x = 0;
y = 0;
z = 0;
/* 到这里已确定触发了长按事件,接下来执行长按后要做的其他事情 */
}
}, false);
}
}
</script>

哎呀,我怎么可能直接甩了代码扭头就走呢!接下来请看~

讲解版本的代码

<script>
let x = 0,//用于记录clientX
y = 0,//用于记录clientY
z = 0,//用于判断,是否是已按住并超过了设定时间。
timer1 = null;//用于定时器
export default {
mounted(){
let oDiv = document.getElementById('canvas');
// 因为长按事件要加在div#canvas上的,如果事件是任何地方的话,就是document /* 添加touchstart,手指触摸事件 */
oDiv.addEventListener("touchstart", function(e) {
/* 阻止默认事件,其实这里ie的兼容写法returnValue没必要*/
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
/* 移动时触发touchmove导致多个touches对象,所以可以直接跳出*/
if (e.touches.length > 1) {
return false;
}
/* 这里有历史渊源的,是第二次点击的时候,把z的值还原。*/
z = 0;
/* 手指一旦触摸屏幕,就开启一个倒计时定时器timer1 */
timer1 = setTimeout(function() {
z = 1; // 如果倒计时结束还没有清楚定时器的话,就把z赋值为1,这样,当判断z=1就说明按住屏幕的时间达到了开发者设定的长按时间。也就是满足了长按事件
}, 500);
/* 手指一旦触摸屏幕,要立即做的第二件事:记录触摸时的点的位置,并存在x,y两个变量里*/
x = e.touches[0].clientX;
y = e.touches[0].clientY;
}, false); /* 绑定第二个事件touchmove,手指在屏幕上连续滑动时连续地触发*/
oDiv.addEventListener("touchmove", function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
/*判断,因为每次手指移动会连续触发touchmove,也就会不停的往event事件对象里边添加“跟踪触摸属性touches”*/
//这个属性是一个数组,每次新添加的都会在最前边。所以每次获取数组里边的第一个对象对应的clientX和clientY,就是实时的移动点的位置
//找这个点的作用,就是为了监听用户,是否按住还移动了。如果移动了,那不能算长按事件(不过这个也看产品需求,如果按住也要触发长按规定那个逻辑的话,这不要判断)
if (x != e.touches[0].clientX || y != e.touches[0].clientY) {
// 具体的判断方法,还记得touchstar那里已经记录了'起跑点'了,只要和x,y的值进行比较,与两个的值有任意一个不等,就是移动了。
// 那么移动的话,先要清除事先埋伏的定时器timer1.要不然,虽然不是长按事件但是倒计时还在进行中。
clearTimeout(timer1);
return false;//除掉'后患'后,安心的结束本次用户的触摸事件监听。
}
}, false); /* 添加第三个触摸事件touchend,这个事件的场景就是用户手指从屏幕拿开时触发*/
oDiv.addEventListener("touchend", function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
/* 上文已经介绍,当用户拿开的时候,只要判断用户从点击到拿开的时间。而记录时间长度比较麻烦,所以当时用了定时器,设定了一个我们想要的时间,时间到了就改变一个状态值z,所以这里我们只要判断z是否被改变即可*/
if (z != 1) {
/* 如果用户手指头拿开的时候,z还是0,即不等于1,说明定时器还没被触发,也就说明没有达到长按的时间,那么不用期待了,同touchmove寿终正寝时要做的一样,清除定时器即可。*/
clearTimeout(timer1);
/* 但是,touchend和touchmove还有一点不一样的,touchend是end(废话),touchmove不管move多少次,最终手指总要从屏幕拿开的,这就是他的关键点。而拿开就是结束,结束,是整个这次触摸生命过程的结束。*/
/* 所以,end还要做的事是初始化,是还原。他需要把x,y的值归为原始。以为了下次再次触发touchstart时做准备。好感人的故事。*/
x = 0;
y = 0;
return false;//然后安心的“死去”。
} else if(z=1){
/* 如果,触发了长按事件,终于触发了长按事件!*/
/* 他还是不能得意忘形,在大展宏图之前,还是要做点准备,打扫一下战场,将各个变量初始化 */
x = 0;
y = 0;
z = 0; /* 然后,他才能开心的做自己计划已久的事业:执行长按后要做的其他事情 */
/* 是什么事情呢? 五点半了,吃饭。*/
}
}, false);
}
}
</script>

奥,对了还有个现象,在与vue中的swiper一同食用时,长按住并且滑动会触发上/下翻页。如果touchmove里边还要有什么动作的话,加上swiper体验很不好。

2018-07-07  17:35:31

JS案例 - 基于vue的移动端长按手势的更多相关文章

  1. 追求极致的用户体验ssr(基于vue的服务端渲染)

    首先这篇博客并不是ssr建议教程,需要ssr入门的我建议也不要搜索博客了,因为官网给出了详细的入门步骤,只需要step by step就可以了,这篇博客的意义是如何使用ssr,可能不同的人有不同的意见 ...

  2. 前端 go.js 流程图基于vue开发项目案例

    一.流程图效果 最近一段时间在研究go.js,它是一款前端开发画流程图的一个插件,也是一个难点,要说为什么是难点,首先,它是依赖画布canvas知识开发.其次,要依赖于内部API开发需求,开发项目需求 ...

  3. 基于vue的移动端web音乐播放器

    声明 以下只是学习完慕课网huangyi老师实战视频课程的笔记内容,仅供个人参考学习使用.如果对Vue2.0实战高级-开发移动端音乐WebApp感兴趣的话,请移步这里:https://coding.i ...

  4. 【Vue.js】基于vue的实时搜索,在结果中高亮显示关键词

    一.搜素效果如下: 二.核心 1)利用oninput属性来触发搜素功能 2)利用RegExp来对字符串来全局匹配关键字,利用replace方法来对匹配的关键字进行嵌入高亮的<span class ...

  5. vue在移动端使用alloyfinger手势库操作图片拖拽、缩放

    最近开发一个活动需要在手机上给上传的头像加上边框.装饰,需要拖拽.手势缩放边框下的头像图片,因为是vue项目,开始尝试了vue-drag-resize这个组件,对图片拖拽支持很完美,但是无法手势缩放, ...

  6. 第一个Vue.js案例

    第一个Vue.js案例 使用Vue有如下几步 引入文件头 加入数据输出框 创建Vue对象,定义数据 案例: <!DOCTYPE html> <html lang="en&q ...

  7. 基于VUE.JS的移动端框架Mint UI

    Mint UI GitHub:github.com/ElemeFE/mint 项目主页:mint-ui.github.io/# Demo:elemefe.github.io/mint- 文档:mint ...

  8. 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框

    vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ...

  9. Vue项目中使用基于Vue.js的移动组件库cube-ui

    cube-ui 是滴滴公司的技术团队基于 Vue.js 实现的精致移动端组件库.很赞,基本场景是够用了,感谢开源!感谢默默奉献的你们. 刚爬完坑,就来总结啦!!希望对需要的朋友有小小的帮助. (一)创 ...

随机推荐

  1. 【Access-Control-Allow-Origin】跨域问题

    [前言] 在实际项目中,可能是多个项目共同完成某个功能,他们之间需要实现数据的交互.这样就会需要有跨域的问题. 比如,发布在不同电脑上的不同项目之间,用不同语言开发的项目之间…… [JSONP] 当使 ...

  2. C# Http访问帮助类,支持get post请求文件下载 [

    using System; using System.Collections.Generic; using System.Collections.Specialized; using System.I ...

  3. 让小区运营再智能一点,EasyRadius正式向WayOs用户提供到期弹出式提示充值页面

    其实一直没向用户提供到期弹出式页面,主要是给VIP群的用户一点优越感,随着这次EasyRadius的更新,海哥就免费向普通easyRadius用户提供这两个模板下载. 有些人会问,什么样的模板.有什么 ...

  4. iOS: 定义 Block

    定义 typedef void (^RFAudioBasicBlock) (void); typedef void (^RFAudioSuccessBlock) (BOOL flag); typede ...

  5. iOS :ViewDidAppear

    进入一个 UIViewController 会调用它的三个方法,分别是 viewDidLoad, viewWillAppear, viewDidAppear. 如每个方法的名字一样,在不同的方法中要处 ...

  6. 移动端H5地图离线瓦片方案(1)(2)

    2在作者另一篇 移动端H5地图离线瓦片方案   文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 移动端的网速和 ...

  7. Java、C#双语版HttpHelper类(解决网页抓取乱码问题)

    在做一些需要抓取网页的项目时,经常性的遇到乱码问题.最省事的做法是去需要抓取的网站看看具体是什么编码,然后采用正确的编码进行解码就OK了,不过总是一个个页面亲自去判断也不是个事儿,尤其是你需要大量抓取 ...

  8. in语句导致查询很慢

    1.表A,表B,表C.其中A中的主键是B的外键,一对多的关系:B的主键是C的外键,一对多的关系.最终想查出所有符合条件的C. 原因:开发人员将A表数据先查出来,放到list中,然后用list作为in的 ...

  9. 织梦漏洞可疑PHP文件/article文件夹

    常见可疑文件夹: 1:article文件夹:最近很多织梦系统网站根目录被上传article文件件,里面有很多赌博静态违法html页面,可疑直接删除,此类违法信息大部分是由于您的网站存在dedecms安 ...

  10. Java利用while循环计算1+1/2!+1/3!……+1/20!

    编写程序,用while语句计算1+1/2!+1/3!……+1/20!,并在控制泰山输出计算结果.要求1+1/2!+1/3!……+1/20!,其实就是求1+1*1/2+1*1/2*1/3+……+1*1/ ...