方法一:
首先,在拖动 div 时,判断当前容器 div 是否有滚动条,如果没有,则禁止整个 div 拖动,例:
1 2 3 4 5 6 |
const list_dom: any = document.querySelector(".list"); list_dom.addEventListener("touchmove",(ev) => { if (list_dom.scrollHeight <= list_dom.clientHeight &&list_dom.offsetHeight <= list_dom.clientHeight) { ev.preventDefault(); } },{ passive: false }); |
注:上述方法仅适用于 div 内没有其他内容滚动情形!如果内层有其他 div 滚动,则需要监听当前滑动区域是否在内层滚动 div 上,如果在对应滚动 div 上,则不调用 ev.preventDefault() 方法,否则则调用。
在配置上述方法同时,对相应存在滚动的 div 设置 css 属性:
1 |
overscroll-behavior: none; |
使临近滚动区域不受到滚动链影响,滚动到边界后不会带动外层滚动。
方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
export const getClientHeight = () => { return ( window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight ); }; /* * @Function 处理touchmove, 将滚动条拖到边缘的时候,禁止橡皮筋效果 */ class HandleTouchMove { startX; startY; constructor() { this.startX = 0; this.startY = 0; this.listenTouchstart = this.listenTouchstart.bind(this); this.listenTouchmove = this.listenTouchmove.bind(this); } listenTouchstart = (ev: any) => { this.startX = ev.changedTouches[0].pageX; this.startY = ev.changedTouches[0].pageY; }; listenTouchmove = (ev: any, _dom: any) => { const dom = document.querySelector(_dom); const moveEndX = ev.changedTouches[0].pageX; const moveEndY = ev.changedTouches[0].pageY; const moveX = moveEndX - this.startX; const moveY = moveEndY - this.startY; if (Math.abs(moveX) > Math.abs(moveY) && moveX > 0) { // 向右拖拽 if (dom?.scrollLeft === 0) { ev.cancelable && ev.preventDefault(); } } if (Math.abs(moveX) > Math.abs(moveY) && moveX < 0) { // 向左拖拽 if ( dom?.scrollLeft + dom?.offsetWidth === dom?.scrollWidth && dom?.scrollLeft + dom?.clientWidth === dom?.scrollWidth ) { ev.cancelable && ev.preventDefault(); } } if (Math.abs(moveY) > Math.abs(moveX) && moveY > 0) { // 向下拖拽 if (dom?.scrollTop === 0) { ev.cancelable && ev.preventDefault(); } } if (Math.abs(moveY) > Math.abs(moveX) && moveY < 0) { // 向上拖拽 if ( dom?.scrollTop + dom?.offsetHeight === dom?.scrollHeight && dom?.scrollTop + dom?.clientHeight === dom?.scrollHeight ) { ev.cancelable && ev.preventDefault(); } } }; } export const handleTouchmove = new HandleTouchMove(); |
调用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<template> <div class="wrap" :style="{ height: client_height }"> <div class="content" @touchstart="handleTouchmove.listenTouchstart" @touchmove=" (ev) => handleTouchmove.listenTouchmove(ev, 'content') "> <div style="height: 1000px">132</div> </div> </div> </template> <script lang="ts" setup> import { getClientHeight, handleTouchmove } from "@/components/Common/utils"; import { onMounted, ref } from "vue"; const client_height: any = ref("100vh"); onMounted(() => { client_height.value = getClientHeight() + "px"; }); </script> <style lang="scss" scoped> .wrap { width: 100%; .content { height: 100%; overflow-y: auto; overscroll-behavior: none; } } @supports (padding-bottom: env(safe-area-inset-bottom)) or (padding-bottom: constant(safe-area-inset-bottom)) { .content { padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */ padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */ } } @supports not (padding-bottom: env(safe-area-inset-bottom)) { .content { padding-bottom: 20px; } } @supports not (padding-bottom: constant(safe-area-inset-bottom)) { .content { padding-bottom: 20px; } } </style> |