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