移动端触摸事件初探

移动端项目做了不少了,但之前很多交互还是依托click相关事件实现的,功能上的需求也都实现了,但自己总感觉不合适,这次又拿到个移动端的需求,决定去用touch相关事件去实现。代码的话,也是网上找的,虽然拿过来用的时候直接报错一点都没执行,但自己改了改,最后能用了,就以他为模板了。

我印象里,html标签似乎没有什么ontouch,ontouchstart这样的触发事件,反正我编辑工具似乎不支持,强行写也没触发过。这次的尝试涉及到了很多没了解过的功能,下面开始一一介绍吧。

判断浏览器是否支持touch事件

touch事件嘛,和click事件不一样,最起码设备得支持,要是PC端使,方法全不执行咋整,所以先来个判断。

('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch

这个方法,对于支持触摸事件的浏览器,返回值是 true ,不支持的,就是 undefined 了。在这,模板中判断方法是这样的:

if(!!self.touch)	//这里self.touch指的是上面那行代码了

又是一个没见过的科技,找度娘,又涨了一波姿势:

js中!的用法是比较灵活的,它除了做逻辑运算常常会用!做类型判断,可以用!与上对象来求得一个布尔值
!可将变量转换成boolean类型,null、undefined和空字符串取反都为false,其余都为true。
!!常常用来做类型判断,在第一步!(变量)之后再做逻辑取反运算

判断浏览器是否支持touch事件,就这样解决了。

添加 addEventListener 方法

addEventListener用来绑定事件,我不了解JS的addEventListener()和JQ的on()有多大区别,反正在这用on是报错了。在这,给body绑定上了touchstart事件(代码在初始化部分可见)。
拿到模板执行时,控制面板提示.addEventListener is not a function,又去找度娘,得到的答案是这是因为选择器没有正确选择元素对象,我的代码中,是通过类名定位元素,捕捉到的是该类名元素的数组,又解决一个新问题。

判断触发触摸事件后的状态

addEventListener第二个参数可以传一个对象,这样会调用该对象的handleEvent属性(事件会自动在传入对象中寻找handleEvent方法),这就有了去做状态判断的基础,通过判断触摸状态,去执行对应的方法。具体方法如下:

 handleEvent:function(event){
                var self = this;     //this指events对象
                if(event.type == 'touchstart'){
                    self.start(event);
                }else if(event.type == 'touchmove'){
                    self.move(event);
                }else if(event.type == 'touchend'){
                    self.end(event);
                }
            },

触摸开始,触摸移动,触摸结束

这三个状态的话,触摸开始主要是需要纪录按下的位置,用于之后的计算,并向目标元素绑定touchmove和touchend方法;触摸移动需要做的事就是判断下有没有多指操作,并记录手指位置;触摸结束,判断手指在整个行为过程中移动方向,添加对应的方法。代码如下:

 //滑动开始
            start:function(event){
                var touch = event.targetTouches[0];     //touches数组对象获得屏幕上所有的touch,取第一个touch
                startPos = {x:touch.pageX,y:touch.pageY,time:+new Date};    //取第一个touch的坐标值
                isScrolling = 0;   //这个参数判断是垂直滚动还是水平滚动,默认0位水平,1为垂直
                body.addEventListener('touchmove',this,false);
                body.addEventListener('touchend',this,false);
            },
            //移动
            move:function(event){
                //当屏幕有多个touch或者页面被缩放过,就不执行move操作
                if(event.targetTouches.length > 1 || event.scale && event.scale !== 1) return;
                var touch = event.targetTouches[0];
                endPos = {x:(touch.pageX - startPos.x),y:(touch.pageY - startPos.y)};
                isScrolling = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1:0;    //isScrolling为1时,表示纵向滑动,0为横向滑动
                //若有需要触摸跟随的实践在此处添加
            },
            //滑动释放
            end:function(event){
                var duration = +new Date - startPos.time;    //滑动的持续时间
//                console.log(isScrolling);
                if(isScrolling == 1){    //当为垂直滚动时
                    if(Number(duration) > 10){  //滑动时间大于10ms
                        //判断是左移还是右移,当偏移量大于10时执行
                        if(endPos.y > 10){
                            console.log("向下");
                        }else if(endPos.y < -10){
                            console.log("向上");
                        }
                    }
                }else{
                    if(Number(duration) > 10){
                        //判断是左移还是右移,当偏移量大于10时执行
                        if(endPos.x > 10){
                            console.log("向右");
                        }else if(endPos.x < -10){
                            console.log("向左");
                        }
                    }
                }
                //解绑事件
                body.removeEventListener('touchmove',this,false);
                body.removeEventListener('touchend',this,false);

对整个方法来说,手指离开屏幕时,我刚写的方法也完成了,这时候记得解绑按下时绑定的方法。

init 初始化

之前在别人写的小插件中也见过,但我这种野路子出身的,完全不了解,不会用,也就是百度大概看看,有个似懂非懂的了解。近期和其他公司合作完成项目时见到对方后台都在页面上用init,坚定了我这次尝试的想法。
目前我对他的理解,觉得它就是用来初始化的,可以绑定事件,也是一个方法函数,表述不是太清楚,要是有了解的,希望可以指正。顺带贴出这块的相关代码。

<script>
	 var body = $("body")[0];	//这里就拿body作为绑定事件的对象吧
     var slider = {
        //判断设备是否支持touch事件
        touch:('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
        slider:body,
         events:{/*这里就不重复了*/},
         //初始化
         init:function(){
            var self = this;     //this指slider对象
            if(!!self.touch){
                self.slider.addEventListener('touchstart',self.events,false);
                //addEventListener第二个参数可以传一个对象,会调用该对象的handleEvent属性
            }
        }
    };
    slider.init();
</script>

其他小技巧

除了一开始的 !! ,模板中还有好几个值得学习的技巧:
记录触摸位置时,没有设置多个变量,用一组数据完成了:

startPos = {x:touch.pageX,y:touch.pageY,time:+new Date};

使用的时候,直接用startPos.x+new Date也是个我没见过的科技,它等同于Date.prototype.valueOf(),功能是获取当前的毫秒时间戳。

最后,附上我完整的页面

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>touch事件测试</title>
    <style>
	    .page{
		    width: 100vw;
		    height: 100vh;
		    font-size: 18px;
		    color: #ffffff;
		    line-height: 100vh;
		    text-align: center;
		}
		.red{
		    background: #ef4641;
		}
		.blue{
		    background: #096bf2;
		}
		.yellow{
		    background: yellow;
		}
		.grey{
		    background: #f5f5f5;
		}
    </style>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div class="page red">
    滑动切换
</div>
<div class="page yellow">
    滑动切换
</div>
<div class="page blue">
    滑动切换
</div>
<div class="page grey">
    滑动切换
</div>
<script>
    var body = $("body")[0];
    var slider = {
        //判断设备是否支持touch事件
        touch:('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
        slider:body,
        //事件
        events:{
            //index:0,     //显示元素的索引
            //slider:this.slider,     //this为slider对象
            handleEvent:function(event){
                var self = this;     //this指events对象
                if(event.type == 'touchstart'){
                    self.start(event);
                }else if(event.type == 'touchmove'){
                    self.move(event);
                }else if(event.type == 'touchend'){
                    self.end(event);
                }
            },

            //滑动开始
            start:function(event){
                var touch = event.targetTouches[0];     //touches数组对象获得屏幕上所有的touch,取第一个touch
                startPos = {x:touch.pageX,y:touch.pageY,time:+new Date};    //取第一个touch的坐标值
                isScrolling = 0;   //这个参数判断是垂直滚动还是水平滚动,默认0位水平,1为垂直
                body.addEventListener('touchmove',this,false);
                body.addEventListener('touchend',this,false);
            },
            //移动
            move:function(event){
                //当屏幕有多个touch或者页面被缩放过,就不执行move操作
                if(event.targetTouches.length > 1 || event.scale && event.scale !== 1) return;
                var touch = event.targetTouches[0];
                endPos = {x:(touch.pageX - startPos.x),y:(touch.pageY - startPos.y)};
                isScrolling = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1:0;    //isScrolling为1时,表示纵向滑动,0为横向滑动
                //若有需要触摸跟随的事件在此处添加
            },
            //滑动释放
            end:function(event){
                var duration = +new Date - startPos.time;    //滑动的持续时间
//                console.log(isScrolling);
                if(isScrolling == 1){    //当为垂直滚动时
                    if(Number(duration) > 10){  //滑动时间大于10ms
                        //判断是左移还是右移,当偏移量大于10时执行
                        if(endPos.y > 10){
                            console.log("向下");
                        }else if(endPos.y < -10){
                            console.log("向上");
                        }
                    }
                }else{
                    if(Number(duration) > 10){
                        //判断是左移还是右移,当偏移量大于10时执行
                        if(endPos.x > 10){
                            console.log("向右");
                        }else if(endPos.x < -10){
                            console.log("向左");
                        }
                    }
                }
                //解绑事件
                body.removeEventListener('touchmove',this,false);
                body.removeEventListener('touchend',this,false);
            }
        },

        //初始化
        init:function(){
            var self = this;     //this指slider对象
            if(!!self.touch){
                self.slider.addEventListener('touchstart',self.events,false);
                //addEventListener第二个参数可以传一个对象,会调用该对象的handleEvent属性
            }
        }
    };
    slider.init();
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值