移动端事件

214 阅读9分钟

移动端3大事件

  • 手指按下

ontouchstart

  • 手指移动

ontouchmove

  • 手指抬起

ontouchend

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <title>Document</title>
    <style>
        #div1 {
            width: 200px;
            height: 200px;
            background: red;
        }
    </style>
</head>

<body>
    <div id="div1"></div>
    <script type="text/javascript">
        var div = document.getElementById('div1');
        div.addEventListener('touchstart', start);
        div.addEventListener('touchmove', move);
        div.addEventListener('touchend', end);
        function start() {
            console.log('按下');
        }
        function move() {
            console.log('移动');
        }
        function end() {
            console.log('抬起');
        }
    </script>
</body>

</html>

移动端阻止pc事件的优点

  1. pc上的事件比移动端的事件略慢,大概是在300ms左右
  2. 阻止pc事件
  3. 下层不要使用有点击(焦点)特性的元素
  4. IOS10下设置meta禁止用户缩放是不可行的。(使用阻止pc事件就可以在IOS10下禁止用户缩放)
  5. 解决IOS10下溢出隐藏的问题。
  6. 禁止系统默认的滚动条、阻止橡皮筋效果
  7. 禁止长按选中文字、选中图片、系统默认菜单
  8. 解决点透问题
  9. 也阻止了焦点元素的焦点行为(要正常使用:ev.stopPropagation()阻止冒泡)

移动端的事件对象

当给某个元素加上了事件绑定函数之后,事件函数默认的第一个参数就是事件对象

事件对象:

当用户在浏览器下触发了某个行为,事件对象会记录用户操作时一些细节信息。

touches 当前位于*屏幕*上的所有手指的一个列表

targetTouches 位于当前DOM元素上的手指的一个列表

changedTouches 涉及当前事件的手指的一个列表

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width,user-scalable=no"/>
	<title>Document</title>
<style>
body,html{
	width: 100%;
	overflow: hidden;
}
#div1{
	width:200px;
	height: 200px;
	background: red;
	position: absolute;
	top:0;
	left:0;
	font-size:50px;
	color: #fff;
}	.;
</style>
</head>
<body>
	<div id="div1"></div>
<script type="text/javascript">
	document.addEventListener('touchstart',function(ev){
		ev.preventDefault();
	});
	var div = document.getElementById('div1');
	div.addEventListener('touchmove',start);
	function start(ev){
		//this.innerHTML = ev.touches.length;
		//this.innerHTML = ev.targetTouches.length;
		this.innerHTML = ev.changedTouches.length;
	}
</script>
</body>
</html>

移动端常用事件封装

tap事件

function tap(el, fn) {
    var startPoint = {};
    el.addEventListener('touchstart', function (e) {
        startPoint = {
            x: e.changedTouches[0].pageX,
            y: e.changedTouches[0].pageY
        }
    });
    el.addEventListener('touchend', function (e) {
        var nowPoint = {
            x: e.changedTouches[0].pageX,
            y: e.changedTouches[0].pageY
        }
        if (Math.abs(nowPoint.x - startPoint.x) < 5 &&
            Math.abs(nowPoint.y - startPoint.y) < 5) {
            fn && fn.call(el, e);
        }
    });
}

无缝滚动效果

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,user-scalable=no">
    <title>Document</title>
    <script type="text/javascript">
        //获取html
        var html = document.documentElement;
        //设置html的字体大小 = 可视区的宽度 / 15
        html.style.fontSize = html.clientWidth / 15 + 'px';
        //阻止pc和浏览器默认行为。
        document.addEventListener('touchstart', function(ev) {
            ev.preventDefault();
        });
    </script>
    <style>
        body {
            margin: 0;
        }
        
        .wrap {
            height: 4.68rem;
            position: relative;
        }
        
        .list {
            padding: 0;
            margin: 0;
            width: 400%;
            position: absolute;
            top: 0;
            left: 0;
            list-style: none;
        }
        
        .list li {
            float: left;
            width: 15rem;
        }
        
        .list img {
            width: 15rem;
            display: block;
        }
        
        nav {
            width: 15rem;
            height: 10px;
            position: absolute;
            bottom: 5px;
            z-index: 1;
            text-align: center;
        }
        
        nav a {
            width: 15px;
            height: 15px;
            display: inline-block;
            background: red;
            border-radius: 50%;
            vertical-align: top;
        }
        
        nav a.active {
            background: #fff;
        }
    </style>
</head>
<body>
    <section class="wrap">
        <ul class="list">
            <li>
                <img src="img/img.jpg" alt="" />
            </li>
            <li>
                <img src="img/img2.jpg" alt="" />
            </li>
            <li>
                <img src="img/img3.jpg" alt="" />
            </li>
            <li>
                <img src="img/img4.jpg" alt="" />
            </li>
        </ul>
        <nav>
            <a href="javascript:;" class="active"></a>
            <a href="javascript:;"></a>
            <a href="javascript:;"></a>
            <a href="javascript:;"></a>
        </nav>
    </section>
    <script type="text/javascript">
        var wrap = document.querySelector('.wrap'),
            list = document.querySelector('.list'),
            a = document.querySelectorAll('a'),
            disX = 0, //按下的坐标
            listL = 0, //当前按下list的left值
            w = wrap.clientWidth, //一张图片的宽度
            len = 0,
            n = 0; //默认第一个小点为白色
        list.innerHTML += list.innerHTML;
        len = list.children.length;
        list.style.width = w * len + 'px';
        list.addEventListener('touchstart', start);
        list.addEventListener('touchmove', move);
        list.addEventListener('touchend', end);
        function start(ev) {
            var e = ev.changedTouches[0];
            disX = e.pageX;
            list.style.transition = 'none';
            var num = Math.round(list.offsetLeft / w);
            if (num == 0) {
                num = a.length;
                list.style.left = -num * w + 'px';
            }
            if (-num == len - 1) {
                num = a.length - 1;
                list.style.left = -num * w + 'px';
            }
            listL = this.offsetLeft;
        }
        function move(ev) {
            var e = ev.changedTouches[0];
            list.style.left = (e.pageX - disX) + listL + 'px';
        }
        function end() {
            var num = Math.round(list.offsetLeft / w);
            list.style.transition = '.5s';
            list.style.left = num * w + 'px';

            //console.log(-num)
            a[n].className = '';
            a[-num % a.length].className = 'active';
            n = -num % a.length;
        }
    </script>
</body>

</html>

移动端时间运动函数库

var Tween = {
	linear: function (t, b, c, d){
		return c*t/d + b;
	},
	easeIn: function(t, b, c, d){
		return c*(t/=d)*t + b;
	},
	easeOut: function(t, b, c, d){
		return -c *(t/=d)*(t-2) + b;
	},
	easeBoth: function(t, b, c, d){
		if ((t/=d/2) < 1) {
			return c/2*t*t + b;
		}
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInStrong: function(t, b, c, d){
		return c*(t/=d)*t*t*t + b;
	},
	easeOutStrong: function(t, b, c, d){
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	easeBothStrong: function(t, b, c, d){
		if ((t/=d/2) < 1) {
			return c/2*t*t*t*t + b;
		}
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	elasticIn: function(t, b, c, d, a, p){
		if (t === 0) { 
			return b; 
		}
		if ( (t /= d) == 1 ) {
			return b+c; 
		}
		if (!p) {
			p=d*0.3; 
		}
		if (!a || a < Math.abs(c)) {
			a = c; 
			var s = p/4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	elasticOut: function(t, b, c, d, a, p){
		if (t === 0) {
			return b;
		}
		if ( (t /= d) == 1 ) {
			return b+c;
		}
		if (!p) {
			p=d*0.3;
		}
		if (!a || a < Math.abs(c)) {
			a = c;
			var s = p / 4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},    
	elasticBoth: function(t, b, c, d, a, p){
		if (t === 0) {
			return b;
		}
		if ( (t /= d/2) == 2 ) {
			return b+c;
		}
		if (!p) {
			p = d*(0.3*1.5);
		}
		if ( !a || a < Math.abs(c) ) {
			a = c; 
			var s = p/4;
		}
		else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		if (t < 1) {
			return - 0.5*(a*Math.pow(2,10*(t-=1)) * 
					Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		}
		return a*Math.pow(2,-10*(t-=1)) * 
				Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
	},
	backIn: function(t, b, c, d, s){
		if (typeof s == 'undefined') {
		   s = 1.70158;
		}
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	backOut: function(t, b, c, d, s){
		if (typeof s == 'undefined') {
			s = 2.70158;  //回缩的距离
		}
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}, 
	backBoth: function(t, b, c, d, s){
		if (typeof s == 'undefined') {
			s = 1.70158; 
		}
		if ((t /= d/2 ) < 1) {
			return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		}
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	bounceIn: function(t, b, c, d){
		return c - Tween['bounceOut'](d-t, 0, c, d) + b;
	},       
	bounceOut: function(t, b, c, d){
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
		}
		return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
	},      
	bounceBoth: function(t, b, c, d){
		if (t < d/2) {
			return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
		}
		return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
	}
};
function css(element, attr , val){
	if(attr == "scale"||attr == "scaleX"
	||attr == "scaleY"||attr == "scaleZ"
	||attr == "rotateX"||attr == "rotateY"
	||attr == "rotateZ"||attr == "rotate"
	||attr == "skewX"||attr == "skewY"
	||attr == "translateX"||attr == "translateY"
	||attr == "translateZ") {
		return cssTransform(element, attr, val);
	}
	if(arguments.length == 2){
		var val = getComputedStyle(element)[attr];
		if(attr=='opacity'){
			val = Math.round(val*100);
		}
		return parseFloat(val);
	} 
	if(attr == "opacity") {
		element.style.opacity= val/100;
	} else {
		element.style[attr]= val + "px";	
	}
}
function cssTransform(element, attr, val){
	if(!element.transform){
		element.transform = {};
	}	
	if(typeof val === "undefined"){ 
		if(typeof element.transform[attr] === "undefined"){
			switch(attr){
				case "scale":
				case "scaleX":
				case "scaleY":
				case "scaleZ":
					element.transform[attr] = 100;
					break;
				default:
					element.transform[attr] = 0;	
			}
		} 
		return element.transform[attr];
	} else {
		element.transform[attr] = val;
		var transformVal  = "";
		for(var s in element.transform){
			switch(s){
				case "scale":
				case "scaleX":
				case "scaleY":
				case "scaleZ":
					transformVal += " " + s + "("+(element.transform[s]/100)+")";
					break;
				case "rotate":
				case "rotateX":
				case "rotateY":
				case "rotateZ":
				case "skewX":
				case "skewY":
					transformVal += " " + s + "("+element.transform[s]+"deg)";
					break;
				default:
					transformVal += " " + s + "("+element.transform[s]+"px)";				
			}
		}
		element.style.WebkitTransform = element.style.transform = transformVal;
	}
}
function MTween(init){
	var t = 0;
	var b = {};
	var c = {};
	var d = init.time / 20;
	for(var s in init.target){ 
		b[s] = css(init.el, s); 
		c[s] = init.target[s] - b[s];
	}
	clearInterval(init.el.timer); 
	init.el.timer = setInterval(
		function(){
			t++;
			if(t>d){
				clearInterval(init.el.timer);
				init.callBack&&init.callBack.call(init.el);
			} else {
				init.callIn&&init.callIn.call(init.el);
				for(var s in b){
					var val = Number((Tween[init.type](t,b[s],c[s],d)).toFixed(2));
					css(init.el, s, val);
				}
			}
		},
		20
	);
}

运用上面函数做一个移动端滑屏效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <title>Document</title>
    <style type="text/css">
        body {
            margin: 0;
        }
        
        body,
        html {
            height: 100%;
            overflow: hidden;
            position: relative;
        }
        
        header {
            height: 40px;
            font-size: 20px;
            color: #fff;
            text-align: center;
            background: #000;
            line-height: 40px;
        }
        
        footer {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            height: 40px;
            color: #fff;
            text-align: center;
            background: #000;
            line-height: 40px;
        }
        
        #wrap {
            position: absolute;
            left: 0;
            right: 0;
            top: 40px;
            bottom: 40px;
            overflow: hidden;
        }
        
        #list {
            margin: 0;
            padding: 0;
            list-style: none;
        }
        
        #list li {
            line-height: 30px;
            text-indent: 20px;
            font-size: 16px;
            border-bottom: 1px solid #000;
        }
    </style>
    <script type="text/javascript" src="m.Tween.js"></script>
    <script type="text/javascript">
        function createList() {
            var list = document.querySelector('#list');
            var inner = "";
            for (var i = 0; i < 300; i++) {
                inner += "<li>这是第" + i + "个li</li>"
            }
            list.innerHTML = inner;
        }
        document.addEventListener('touchstart', function(e) {
            e.preventDefault();
        });
        window.onload = function() {
            createList();
            var wrap = document.querySelector('#wrap');
            mScroll({
                el: wrap,
                offBar: true
            })
        };

        function mScroll(init) {
            if (!init.el) {
                return;
            }
            var wrap = init.el;
            var inner = init.el.children[0];
            var scrollBar = document.createElement("div");
            var startPoint = 0;
            var startEl = 0;
            var lastY = 0;
            var lastDis = 0;
            var lastTime = 0;
            var lastTimeDis = 0;
            var maxTranslate = wrap.clientHeight - inner.offsetHeight;
            if (!init.offBar) {
                var scale = wrap.clientHeight / inner.offsetHeight;
                inner.style.minHeight = "100%";
                scrollBar.style.cssText = "width:6px;background:rgba(0,0,0,.5);position:absolute;right:0;top:0;border-radius:3px;opacity:0;transition:.3s opacity;";
                wrap.appendChild(scrollBar);
            }
            css(inner, "translateZ", 0.01);
            inner.addEventListener('touchstart', function(e) {
                maxTranslate = wrap.clientHeight - inner.offsetHeight;
                if (!init.offBar) {
                    if (maxTranslate >= 0) {
                        scrollBar.style.display = "none";
                    } else {
                        scrollBar.style.display = "block";
                    }
                    scale = wrap.clientHeight / inner.offsetHeight;
                    scrollBar.style.height = wrap.clientHeight * scale + "px";
                }
                clearInterval(inner.timer);
                startPoint = e.changedTouches[0].pageY;
                startEl = css(inner, "translateY");
                lastY = startEl;
                lastTime = new Date().getTime();
                lastTimeDis = lastDis = 0;
                (init.offBar) || (scrollBar.style.opacity = 1);
            });
            inner.addEventListener('touchmove', function(e) {
                var nowTime = new Date().getTime();
                var nowPoint = e.changedTouches[0].pageY;
                var dis = nowPoint - startPoint;
                var translateY = startEl + dis;
                css(inner, "translateY", translateY);
                (init.offBar) || css(scrollBar, "translateY", -translateY * scale);
                lastDis = translateY - lastY;
                lastY = translateY;
                lastTimeDis = nowTime - lastTime;
                lastTime = nowTime;
            });
            inner.addEventListener('touchend', function(e) {
                var type = "easeOut";
                var speed = Math.round(lastDis / lastTimeDis * 10);
                speed = lastTimeDis <= 0 ? 0 : speed;
                var target = Math.round(speed * 50 + css(inner, "translateY"));
                if (target > 0) {
                    target = 0;
                    type = "backOut";
                } else if (target < maxTranslate) {
                    target = maxTranslate;
                    type = "backOut";
                }
                MTween({
                    el: inner,
                    target: {
                        translateY: target
                    },
                    time: Math.round(Math.abs(target - css(inner, "translateY")) * 1.8),
                    type: type,
                    callBack: function() {
                        (init.offBar) || (scrollBar.style.opacity = 0);
                    },
                    callIn: function() {
                        var translateY = css(inner, "translateY");
                        init.offBar || css(scrollBar, "translateY", -translateY * scale);
                    }
                });
            });
        }
    </script>
</head>
<body>
    <header id="header">whs</header>
    <section id="wrap">
        <ul id="list"></ul>
    </section>
    <footer id="footer">前端工程师</footer>
</body>
</html>

摇一摇效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <title>Document</title>
</head>

<body>
    <script type="text/javascript">
        (function() {
            var lastX;
            var lastY;
            var lastZ;
            var maxRang = 80;
            var minRang = 10;
            var isShake = false;
            window.addEventListener('devicemotion', function(e) {
                var motion = e.accelerationIncludingGravity;
                var x = Math.round(motion.x);
                var y = Math.round(motion.y);
                var z = Math.round(motion.z);
                if (typeof lastX == "undefined") {
                    lastX = x;
                    lastY = y;
                    lastZ = z;
                    return;
                }
                var dis = Math.abs(x - lastX) + Math.abs(y - lastY) +
                    Math.abs(z - lastZ);
                if (dis > maxRang) {
                    isShake = true;
                }
                if (dis < minRang && isShake) {
                    isShake = false;
                    //执行 摇一摇之后,要操作的内容
                    alert("您晃动了手机");
                }
                lastX = x;
                lastY = y;
                lastZ = z;
            });
        })();
    </script>
</body>

</html>

多指操作

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <style type="text/css">
        #box {
            margin: 100px auto;
            width: 200px;
            height: 200px;
            background: url(1.jpg) no-repeat;
            background-size: cover;
        }
    </style>
</head>

<body>
    <div id="box"></div>
    <script type="text/javascript" src="m.Tween.js"></script>
    <script type="text/javascript">
        document.addEventListener('touchstart', function(e) {
            e.preventDefault();
        });
        window.onload = function() {
            var box = document.querySelector('#box');
            var startRotate = 0;
            var startScale = 0;
            css(box, "translateZ", 0.01);
            setGesture({
                el: box,
                start: function(e) {
                    startScale = css(this, "scale");
                },
                change: function(e) {
                    css(this, "rotate", startRotate + e.rotation);
                    css(this, "scale", startScale * e.scale);
                }
            })
        };
        function getDis(point1, point2) {
            var x = point2.x - point1.x;
            var y = point2.y - point1.y;
            return Math.sqrt(x * x + y * y);
        }
        function getDeg(point1, point2) {
            var x = point2.x - point1.x;
            var y = point2.y - point1.y;
            return Math.atan2(y, x) * 180 / Math.PI;
        }
        function setGesture(init) {
            var el = init.el;
            var isGestrue = false;
            var startPoint = [];
            if (!el) {
                return;
            }
            el.addEventListener('touchstart', function(e) {
                if (e.touches.length >= 2) {
                    isGestrue = true; //记录当前用户触发了gesture
                    startPoint[0] = {
                        x: e.touches[0].pageX,
                        y: e.touches[0].pageY
                    };
                    startPoint[1] = {
                        x: e.touches[1].pageX,
                        y: e.touches[1].pageY
                    };
                    init.start && init.start.call(el, e);
                }
            });
            el.addEventListener('touchmove', function(e) {
                if (isGestrue && e.touches.length >= 2) {
                    var nowPoint = [];
                    nowPoint[0] = {
                        x: e.touches[0].pageX,
                        y: e.touches[0].pageY
                    };
                    nowPoint[1] = {
                        x: e.touches[1].pageX,
                        y: e.touches[1].pageY
                    };
                    var startDis = getDis(startPoint[0], startPoint[1]);
                    var nowDis = getDis(nowPoint[0], nowPoint[1]);
                    var startDeg = getDeg(startPoint[0], startPoint[1]);
                    var nowDeg = getDeg(nowPoint[0], nowPoint[1]);
                    e.scale = nowDis / startDis;
                    e.rotation = nowDeg - startDeg;
                    init.change && init.change.call(el, e);
                }
            });
            el.addEventListener('touchend', function(e) {
                if (isGestrue) {
                    if (e.touches.length < 2 || e.targetTouches.length < 1) {
                        isGestrue = false;
                        init.end && init.end.call(el, e);
                    }
                }
            });
        }
    </script>
</body>
</html>