前言
在移动端中,当我们的页面既有上下滑动又有左右滑动时,比如我们顶部有轮播图(左右移动),页面还包含上下移动滚动条。当我们斜滑页面,页面也会斜着运动,即触发了左右移动事件又触发了上下移动事件。布局还可能会错乱,这不是我们想要的,我们只想它左右或者上下滑动,不同时滑动。接下来我们来解决这个问题
一、touch触摸事件介绍
- touchstart:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发
- touchmove:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用preventDefault()事件可以阻止默认事件
- touchend:当手指从屏幕上离开的时候触发
- touchcancel:当系统停止跟踪触摸的时候触发。关于这个事件的确切出发时间,文档中并没有具体说明,咱们只能去猜测了
二、TouchEvent 对象
每一个touch事件的触发都会产生一个TouchEvent对象,以下是TouchEvent对象三个比较常用的重要属性
- touches:当前位于屏幕上的所有手指的列表
- targetTouches:位于当前DOM元素上手指的列表
- changedTouches:涉及当前事件手指的列表
wrap.addEventListener("touchstart", (e) => {
console.log(e)
})
三、touchEvent 对象属性
每个Touch对象包含以下属性
- clientX:触摸目标在视口中的x坐标
- clientY:触摸目标在视口中的y坐标
- identifier:标识触摸的唯一ID
- pageX:触摸目标在页面中的x坐标
- pageY:触摸目标在页面中的y坐标
- screenX:触摸目标在屏幕中的x坐标
- screenY:触摸目标在屏幕中的y坐标
- target:触目的DOM节点目标
四、js解决移动端滑动问题(幻灯片案例)
解决思路:监听滑动,预判用户是左右滑动,还是上下滑动,如果水平移动距离 > 垂直移动距离 就是做水平滑动,反之就是垂直滑动,再通过阻止默认事件来解决滑动问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html {
font-size: 10vw;
}
body {
margin: 0;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
#wrap {
position: relative;
width: 100vw;
overflow: hidden;
}
#list {
float: left;
display: flex;
display: -webkit-box;
}
#list li {
flex: none;
width: 100vw;
}
#list img {
width: 100%;
height: 200px;
display: block;
}
.nav {
position: absolute;
left: 0;
bottom: .2rem;
width: 100%;
text-align: center;
vertical-align: top;
}
.nav a {
display: inline-block;
width: .3rem;
height: .3rem;
background: #fff;
margin: 0 .1rem;
border-radius: .15rem;
transition: .3s;
}
.nav .active {
width: .6rem;
color: #fff;
}
.textList {
margin: 0;
padding: 0;
list-style: none;
}
.textList li {
font: 14px/40px "宋体";
padding-left: 20px;
border-bottom: 1px solid #000;
}
</style>
</head>
<body>
<div id="wrap">
<!-- 幻灯片 -->
<ul id="list">
<li><img src="https://i02piccdn.sogoucdn.com/f8773bf41fc728d8" alt=""></li>
<li><img src="https://i02piccdn.sogoucdn.com/03469eff264233a8" alt=""></li>
<li><img src="https://i02piccdn.sogoucdn.com/b8322a9d8751fd62" alt=""></li>
<li><img src="https://i04piccdn.sogoucdn.com/87a97031f6954b64" alt=""></li>
<li><img src="https://i03piccdn.sogoucdn.com/d1eef212d4b16e56" alt=""></li>
</ul>
<!-- 点 -->
<nav class="nav">
<a class="active"></a>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</div>
<!-- 测试数据列表 -->
<ul class="textList"></ul>
<script>
// 生成两百行测试数据列表
{
let list = document.querySelector(".textList");
list.innerHTML = [...(".".repeat(200))].map((item, index) => {
return `<li>这是第${index}行测试数据</li>`;
}).join("");
}
// 幻灯片
/*
在两个方向的滑动上,如果有一些不同的操作,这里要注意我们要进行方向判断
每次滑动时判断方向,一旦判明方向,就不在判断
*/
{
let wrap = document.querySelector("#wrap");
let list = document.querySelector("#list");
let navs = document.querySelectorAll(".nav a");
let startPoint = {};
let translateX = 0;
let startTranslateX = 0;
let now = 0;
let wrapW = wrap.clientWidth;
const range = .3 * wrapW;
let isFirst = true;
let isMove = true;
list.innerHTML += list.innerHTML;
// 当手指触摸屏幕时触发
wrap.addEventListener("touchstart", (e) => {
let touch = e.changedTouches[0];
list.style.transition = "none";
startPoint = {
x: touch.pageX,
y: touch.pageY
};
if (now == 0) {
now = navs.length;
} else if (now == navs.length * 2 - 1) {
now = navs.length - 1;
}
translateX = -now * wrapW;
list.style.transform = `translateX(${translateX}px)`;
startTranslateX = translateX;
isFirst = true;
isMove = true;
});
// 当手指在屏幕上滑动时连续地触发
wrap.addEventListener("touchmove", (e) => {
let touch = e.changedTouches[0];
let nowPoint = {
x: touch.pageX,
y: touch.pageY
};
let dis = {
x: nowPoint.x - startPoint.x,
y: nowPoint.y - startPoint.y
};
// 在安卓下,手指按下时,如果触摸面积比较大,容易误触 touchmove
if (isFirst) {
if (Math.abs(dis.x) - Math.abs(dis.y) > 5) {
// 左右滑动, 阻止滚动条不进行上下滑动,而让幻灯片滑动
isMove = true;
isFirst = false;
} else if (Math.abs(dis.y) - Math.abs(dis.x) > 5) {
// 上下滑动, 不阻止滚动条滑动,禁止幻灯片滑动
isMove = false;
isFirst = false;
}
}
if (isMove) {
e.preventDefault();
if (!isFirst) {
translateX = startTranslateX + dis.x;
list.style.transform = `translateX(${translateX}px)`;
}
}
});
// 当手指从屏幕上离开时触发
wrap.addEventListener("touchend", (e) => {
let touch = e.changedTouches[0];
let nowPoint = {
x: touch.pageX,
y: touch.pageY
};
let dis = {
x: nowPoint.x - startPoint.x,
y: nowPoint.y - startPoint.y
};
if (Math.abs(dis.x) > range && isMove) {
now -= dis.x / Math.abs(dis.x);
}
navs.forEach(item => {
item.classList.remove("active")
});
translateX = -now * wrapW;
list.style.transition = ".3s";
list.style.transform = `translateX(${translateX}px)`;
navs[now % navs.length].classList.add("active");
});
}
</script>
</body>
</html>
五、效果图
六、移动端滚动插件
Swiper: https://github.com/nolimits4web/Swiper
better-scroll: https://ustbhuangyi.github.io/better-scroll/#/zh
文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料
扫描二维码关注公众号,回复:
12874068 查看本文章