移动端滚动条穿透(失去焦点)解决---用touch事件写滑动

效果

可以看到滑动下面的图层后,再滑动(红色边框内的)可滑动部分,不会有卡顿、失去焦点的情况,里面的元素也可以点击。
在这里插入图片描述

问题点

经测试,是因为现在用的移动端的适配(下面的代码)的问题,但是目前没找到更好的,所以先用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 = 差值
        • 否则正常滑动
  • 因为使用了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的块里面写
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值