javascript - 当我在移动设备上触摸我的 JavaScript 滑块时,我无法向下滚动页面
问题描述
我使用纯 JavaScript构建了一个滑块。在移动屏幕上,当我触摸滑块时,我只能更改幻灯片但不能向下滚动页面。
当滑块元素被触摸时,触发“touchstart”事件和相应的事件处理函数,event.preventDefault()
停止滚动页面,然后当“touchmove”事件触发时,代码使用第一个和新的水平坐标和CSS之间的差异向左移动滑块。
我在下面做了一个最小的代码。也可以点击查看在线编辑器上的代码。
const slides = document.querySelector(".slides");
let posX1, posX2, dX;
slides.addEventListener("touchstart", dragStart);
slides.addEventListener("touchmove", dragAction);
function dragStart(e) {
e.preventDefault();
posX1 = e.touches[0].clientX;
}
function dragAction(e) {
posX2 = e.touches[0].clientX;
dX = posX2 - posX1;
posX1 = e.touches[0].clientX;
slides.style.left = (slides.offsetLeft + dX) + "px";
}
body {
padding-bottom: 1000px;
}
.slider {
width: 200px;
height: 100px;
margin: 0 auto;
border: 1px solid black;
position: relative;
overflow: hidden;
}
.slides {
width: 600px;
height: 100px;
display: flex;
position: absolute;
}
.slide {
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.slide:nth-child(1) {
background-color: rgb(200, 200, 200);
}
.slide:nth-child(2) {
background-color: rgb(150, 150, 150);
}
.slide:nth-child(3) {
background-color: rgb(100, 100, 100);
}
<!DOCTYPE html>
<html>
<body>
<div class="slider">
<div class="slides">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
</div>
</body>
</html>
谢谢你的时间 :)
解决方案
我想除了我之外没有人检查过我的问题,但是,假设有一个假设的人和我有同样的问题,我可以解决这个问题:
我想出了如何使用作者在“touchstart”中使用的这篇文章制作一个 JavaScript 滑块” EventListener 和我坚持使用它,但解决方案是简单地调用“touchmove”事件本身的方法而不是“ touchstart”,当然如果你需要(如果用户试图更改幻灯片)。如果用户试图滚动页面,则删除“touchend”EventListener。preventDefault()
preventDefault()
const slides = document.querySelector(".slides");
let posX1,
posX2,
posY1,
posY2,
dX,
dY,
dirDetected = false;
//feature detection
//-------------Note 1-----------//
let passiveIfSupported = false;
try {
window.addEventListener("test", null, Object.defineProperty({}, "passive", {
get: function() {passiveIfSupported = {passive: false};}
}));
} catch(err) {}
slides.addEventListener("touchstart", dragStart, passiveIfSupported);
slides.addEventListener("touchmove", dragAction, passiveIfSupported);
slides.addEventListener("touchend", dragEnd, false);
function dragStart(e) {
posX1 = e.touches[0].clientX;
posY1 = e.touches[0].clientY;
}
function dragAction(e) {
//-------------Note 2-----------//
e.preventDefault();
posX2 = e.touches[0].clientX;
posY2 = e.touches[0].clientY;
dX = posX2 - posX1;
posX1 = e.touches[0].clientX;
dY = posY2 - posY1;
if (!dirDetected) {
if (Math.abs(dY) > Math.abs(dX)) {
slides.removeEventListener("touchmove", dragAction, passiveIfSupported);
return;
}
dirDetected = true;
}
slides.style.left = (slides.offsetLeft + dX) + "px";
}
function dragEnd() {
if (!dirDetected) {
slides.addEventListener("touchmove", dragAction, passiveIfSupported);
}
dirDetected = false;
}
body {
padding-bottom: 1000px;
}
.slider {
width: 200px;
height: 100px;
margin: 0 auto;
border: 1px solid black;
position: relative;
overflow: hidden;
}
.slides {
width: 600px;
height: 100px;
display: flex;
position: absolute;
}
.slide {
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.slide:nth-child(1) {
background-color: rgb(200, 200, 200);
}
.slide:nth-child(2) {
background-color: rgb(150, 150, 150);
}
.slide:nth-child(3) {
background-color: rgb(100, 100, 100);
}
<!DOCTYPE html>
<html>
<body>
<div class="slider">
<div class="slides">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
</div>
</body>
</html>
注1.(addEventListener的第三个参数):注意addEventListener()
方法的第三个参数。我从这个问题的搜索中意识到了一些事情。我将preventDefault()
在“touchmove” EventListener 中使用,但在某些版本的 Chrome 和 Firefox 中,如果您不指定选项对象的被动属性(的第三个参数),则默认值为“touchstart”和“touchmove”addEventListener()
事件设置为 true 并且这不会让 EventListener 调用preventDefault()
,因此您必须将第三个参数设置为{passive: false}
但如果加载脚本的浏览器是旧的,则需要第三个布尔参数addEventListener()
那么你需要提供一个布尔值而不是对象。因此,您可以使用特征检测来提供适当的参数。
注意 2. Firefox 和 chrom android 处理“touchmove” preventDefault() 的方式不同:这是我发现的另一点(来自这个问题),如果你在 Chrome Android 上运行上述代码,它运行良好,你可以滚动页面或更改幻灯片但在Firefox Android 你不能滚动。实际上,我认为这是 Chrome 的错,因为根据“touchmove”事件的规范,如果第一个“touchmove”事件被阻止,那么随后绑定到同一触摸点的“touchmove”事件将被阻止,并且在上面的代码中的第一行我使用的“touchmove”事件处理函数preventDefault()
所以我需要在 if 块之后调用它,以确保在需要时阻止默认行为。
const slides = document.querySelector(".slides");
let posX1,
posX2,
posY1,
posY2,
dX,
dY,
dirDetected = false;
//feature detection
let passiveIfSupported = false;
try {
window.addEventListener("test", null, Object.defineProperty({}, "passive", {
get: function() {passiveIfSupported = {passive: false};}
}));
} catch(err) {}
slides.addEventListener("touchstart", dragStart, passiveIfSupported);
slides.addEventListener("touchmove", dragAction, passiveIfSupported);
slides.addEventListener("touchend", dragEnd, false);
function dragStart(e) {
posX1 = e.touches[0].clientX;
posY1 = e.touches[0].clientY;
}
function dragAction(e) {
posX2 = e.touches[0].clientX;
posY2 = e.touches[0].clientY;
dX = posX2 - posX1;
posX1 = e.touches[0].clientX;
dY = posY2 - posY1;
if (!dirDetected) {
if (Math.abs(dY) > Math.abs(dX)) {
slides.removeEventListener("touchmove", dragAction, passiveIfSupported);
return;
}
e.preventDefault();
}
dirDetected = true;
slides.style.left = (slides.offsetLeft + dX) + "px";
}
function dragEnd() {
if (!dirDetected) {
slides.addEventListener("touchmove", dragAction, passiveIfSupported);
}
dirDetected = false;
}
body {
padding-bottom: 1000px;
}
.slider {
width: 200px;
height: 100px;
margin: 0 auto;
border: 1px solid black;
position: relative;
overflow: hidden;
}
.slides {
width: 600px;
height: 100px;
display: flex;
position: absolute;
}
.slide {
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.slide:nth-child(1) {
background-color: rgb(200, 200, 200);
}
.slide:nth-child(2) {
background-color: rgb(150, 150, 150);
}
.slide:nth-child(3) {
background-color: rgb(100, 100, 100);
}
<!DOCTYPE html>
<html>
<body>
<div class="slider">
<div class="slides">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
</div>
</body>
</html>
推荐阅读
- c# - 在C#中打印DataGridView时如何计算单元格高度[有长文本]
- html - CSS悬停效果不起作用,我发现它丢失了
- html - SVG中的动画虚线
- java - KeyListener 没有注册按键
- php - 如何获得意甲品牌=
- javascript - Reactour - 如何禁用下一步,直到正确的用户操作?
- python - 让 Python 正确地将用户名输入与 MySQL DB 中的用户名进行比较的问题
- java - Spring Webflux WebClient - 指定发送出站请求时使用的 TLS 版本(介于 TLSv1.2 和 TLSv1.3 之间)
- python - 详尽的特征选择
- javascript - JavaScript:使用 .forEach 向数组项添加新属性