效果
可以看到滑动下面的图层后,再滑动(红色边框内的)可滑动部分,不会有卡顿、失去焦点的情况,里面的元素也可以点击。
问题点
经测试,是因为现在用的移动端的适配(下面的代码)的问题,但是目前没找到更好的,所以先用touch事件写一套
//这段就是有问题的那段适配,目前的项目都是用的这个,有好的再换
(function() {
var _width = 750;
var ua = navigator.userAgent;
if (/Android (\d+\.\d+)/.test(ua)) {
var version = parseFloat(RegExp.$1);
if (version > 2.3) {
document.write('<meta name="viewport" content="width=' + _width +
',user-scalable=no,target-densitydpi=device-dpi,minimal-ui">')
} else {
document.write('<meta name="viewport" content="width=' + _width +
',target-densitydpi=device-dpi">')
}
} else if (/QQAC_Client_iOS/.test(ua)) {
document.write('<meta name="viewport" content="width=' + _width +
',maximum-scale=0.5,minimum-scale=0.5">');
} else {
document.write('<meta name="viewport" content="width=' + _width +
',user-scalable=no,target-densitydpi=device-dpi,minimal-ui">')
}
})();
touch事件滑动的逻辑
- 先获取要滚动的部分(里面的盒子,如下图的蓝色背景颜色的部分,暂且称它为insideBox)和滚动外面的盒子(如下图红色边框部分,暂且称它为outsideBox)的高度,得出差值
- 再获取insideBox当前的top值,滑动时进行更改
- 如果差值是负数,滑动无反应
- 如果差值是正数,可以滑动
- 从上往下滑时
- 如果top <= 0,正常滑动
- 否则top = 0
- 从下往上滑动时
- 如果top <= 0,可以滑动
- 如果top <= -差值,再滑向上动时top = 差值
- 否则正常滑动
- 如果top <= 0,可以滑动
- 从上往下滑时
- 因为使用了touch事件,在点击里面的选项时也需要用touch事件判断一下
代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1" />
<title>touch事件滑动</title>
<script>
(function() {
var _width = 750;
var ua = navigator.userAgent;
if (/Android (\d+\.\d+)/.test(ua)) {
var version = parseFloat(RegExp.$1);
if (version > 2.3) {
document.write('<meta name="viewport" content="width=' + _width +
',user-scalable=no,target-densitydpi=device-dpi,minimal-ui">')
} else {
document.write('<meta name="viewport" content="width=' + _width +
',target-densitydpi=device-dpi">')
}
} else if (/QQAC_Client_iOS/.test(ua)) {
document.write('<meta name="viewport" content="width=' + _width +
',maximum-scale=0.5,minimum-scale=0.5">');
} else {
document.write('<meta name="viewport" content="width=' + _width +
',user-scalable=no,target-densitydpi=device-dpi,minimal-ui">')
}
})();
</script>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: #fff;
}
.page {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.scroll1 {
position: absolute;
left: 0;
top: 0;
width: 400px;
height: 600px;
overflow-x: hidden;
overflow-y: scroll;
border: 2px solid salmon;
}
.scroll1_long {
position: absolute;
left: 0;
/* top: 0; */
width: 100%;
height: auto;
}
.scroll1_long_item {
width: 100%;
height: 60px;
text-align: center;
line-height: 60px;
}
</style>
</head>
<body>
<div class="page">
<div class="scroll1">
<div class="scroll1_long" style="top: 0;">
<div class="scroll1_long_item">啧啧啧1</div>
<div class="scroll1_long_item">啧啧啧2</div>
<div class="scroll1_long_item">啧啧啧3</div>
<div class="scroll1_long_item">啧啧啧4</div>
<div class="scroll1_long_item">啧啧啧5</div>
<div class="scroll1_long_item">啧啧啧6</div>
<div class="scroll1_long_item">啧啧啧7</div>
<div class="scroll1_long_item">啧啧啧8</div>
<div class="scroll1_long_item">啧啧啧9</div>
<div class="scroll1_long_item">啧啧啧10</div>
<div class="scroll1_long_item">啧啧啧11</div>
<div class="scroll1_long_item">啧啧啧12</div>
<div class="scroll1_long_item">啧啧啧13</div>
<div class="scroll1_long_item">啧啧啧14</div>
</div>
</div>
</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script>
touchScroll('scroll1', 'scroll1_long');//调用
let startX,
startY,
moveEndX,
moveEndY,
X,
Y,
startXItem,
startYItem,
moveEndXItem,
moveEndYItem,
XItem,
YItem;
//传入两个值,
//outsideBox是外面固定高度,y轴超出可滚动的盒子
//insideBox是里面被元素撑起高度的长的盒子
function touchScroll(outsideBox, insideBox) {
let outsideBoxHeight = $('.' + outsideBox).height();
insideBoxHeight = $('.' + insideBox).height();
//里面的比外面的多多少,如果是负数,滑动无反应;如果是正数,向上划到top为差值时,再向上划无反应,向下划到top为0时再向下划无反应
maxScrollLength = insideBoxHeight - outsideBoxHeight,
//里面长图现在的top值,根据滑动变化top值
nowTop = parseInt($('.' + insideBox)[0].style.top.split('px')[0]),
//滑动系数,控制滑动速度,数值越小,滑动速度越慢
scrollNum = 0.06;
console.log('nowTop : ' + nowTop);
console.log('outsideBoxHeight : ' + outsideBoxHeight + ' , insideBoxHeight : ' + insideBoxHeight +
' maxScrollLength : ' + maxScrollLength);
//监听滑动方向
$('.' + insideBox).on('touchstart', function(e) {
e.preventDefault();
startX = e.originalEvent.changedTouches[0].pageX,
startY = e.originalEvent.changedTouches[0].pageY;
});
$('.' + insideBox).on('touchmove', function(e) {
e.preventDefault();
moveEndX = e.originalEvent.changedTouches[0].pageX,
moveEndY = e.originalEvent.changedTouches[0].pageY,
X = moveEndX - startX,
Y = moveEndY - startY;
if (maxScrollLength > 0) {
if (Math.abs(X) > Math.abs(Y) && X > 0) {
console.log('left to right');
} else if (Math.abs(X) > Math.abs(Y) && X < 0) {
console.log('right to left');
} else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
console.log('top to bottom');
if (nowTop <= 0) {
nowTop = nowTop + Y * scrollNum;
} else {
nowTop = 0;
}
$('.' + insideBox).css('top', nowTop + 'px');
} else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
console.log('bottom to top');
if (nowTop <= 0) {
if (nowTop <= -maxScrollLength) {
nowTop = -maxScrollLength;
} else {
nowTop = nowTop + Y * scrollNum;
}
$('.' + insideBox).css('top', nowTop + 'px');
}
} else {
console.log('just touch');
}
}
});
$('.' + insideBox).on('touchend', function(e) {
e.preventDefault();
if (maxScrollLength > 0) {
if (nowTop <= -maxScrollLength) {
nowTop = -maxScrollLength;
} else if (nowTop > 0) {
nowTop = 0;
}
$('.' + insideBox).css('top', nowTop + 'px');
}
});
}
//点击里面每个选项
$('.scroll1_long_item').on('touchstart', function(e) {
startXItem = e.originalEvent.changedTouches[0].pageX,
startYItem = e.originalEvent.changedTouches[0].pageY;
})
$('.scroll1_long_item').on('touchend', function(e) {
moveEndXItem = e.originalEvent.changedTouches[0].pageX,
moveEndYItem = e.originalEvent.changedTouches[0].pageY,
XItem = moveEndXItem - startXItem,
YItem = moveEndYItem - startYItem;
if (Math.abs(XItem) == 0 && Math.abs(YItem) == 0) {
alert($(this).text());
}
})
</script>
</html>
注意
- insideBox对应的元素(这里是scroll1_long)应该有定位的元素
- insideBox对应的元素在行内写top属性
- 调用 : touchScroll(outsideBox, insideBox);
- 里面的元素点击需要确认点击时手指头没有滑动,要是只写touchstart或者touchend,滑动时也算。
- 这里只是上下滑动的,左右滑动请在打印出right to left 和 left to right的块里面写