当页面出现浮层的时候,滑动浮层的内容,正常状况下预期应该是浮层下边的内容不会滚动;然而事实并不是如此。 css
先去github上搜索一番,发现有解决此问题的开源包,简单粗暴直接挑选了其中star的最高的(body-scroll-lock)操做一番! 使用后发现有一些问题:html
查源码发现该包在iOS
端使用禁止touchmove
的方式单独处理,可是在其余端只是给body
加overflow: hidden
简单处理。 因而决定写一个针对多端通用的包来处理相似的问题。android
看到下边的滚动确定马上就想到了是整个viewport
的滚动,那么若是给body设置overflow: hidden
,此时body的内容就只有一屏了,确定不会滚动了;ios
body { overflow: hidden; } 复制代码
此方案在pc端完美解决了咱们的问题,然而事情并无那么简单;git
再试试移动端: github
上边想到给body设置overflow: hidden
在移动端并不能解决咱们的问题,是否在于body的height没有设置web
100%
;同时使用这两个操做彷佛完美知足了咱们的需求; chrome
top值
不就定位到咱们想要的位置了(聪明如我)。
tips: body 设置
relative
定位会页面自身拉上去,下边留白npm
屡次实验发现这个方案在android
端中完美达到了咱们想要的结果,可是在ios
端并不理想;每次定位的时候会有闪动的问题;好事多磨,接着探索ios端的方案。浏览器
若是禁止掉页面的touchmove
是否可行呢?话很少说就是干! 当弹出浮层的时候禁掉页面元素的touchmove
document.addEventListener('touchmove', function (event) { event.preventDefault() }) 复制代码
测试发现没有达到想象中的效果,感受这个结果并不能接受啊,禁止document
的touchmove
都不能禁止滚动的吗?
进一步的探索后发现缘由竟是这个属性
原来是浏览器作的一些优化,chrome passive-event-listeners Passive Event Listeners是Chrome提出的一个新的浏览器特性:Web开发者经过一个新的属性passive
来告诉浏览器,当前页面内注册的事件监听器内部是否会调用preventDefault
函数来阻止事件的默认行为,以便浏览器根据这个信息更好地作出决策来优化页面性能。当属性passive
的值为true的时候,表明该监听器内部不会调用preventDefault
函数来阻止默认滑动行为,Chrome浏览器称这类型的监听器为被动(passive)监听器。
知道问题就好说了,给addEventListener
传入第三个参数
document.addEventListener('touchmove', function (event) { event.preventDefault() }, { passive: false }) 复制代码
大功告成! 忽然想到,若是浮层中还须要滚动那就不GG了! so,是否是能够有选择性的禁止滚动(在浮层中元素滚动到最顶部或者最底部以后禁止滚动)。 单独处理浮层中须要滚动的元素;
targetElement.ontouchmove = function (event) { const clientY = event.targetTouches[0].clientY - initialClientY if (targetElement && targetElement.scrollTop === 0 && clientY > 0) { return preventDefault(event) } if (targetElement && (targetElement.scrollHeight - 1 - targetElement.scrollTop <= targetElement.clientHeight) && clientY < 0) { return preventDefault(event) } event.stopPropagation() return true } 复制代码
这个方案在ios
中完美实现,可是在 android
中仍是有一点问题;浮层内容拉到最顶部或者最底部的时候依然会带动页面的内容有必定程度的移动。
终极方案来啦!
tua-body-scroll-lock便是在ios
、android
和PC
各个端单独处理,保证在每一个端均可以实现完美的效果!
$ npm i -S tua-body-scroll-lock # OR $ yarn add tua-body-scroll-lock 复制代码
import { lock, unlock } from 'tua-body-scroll-lock' // 禁止滑动后还须要内部能够滚动的元素(针对移动端ios处理) const targetElement = document.querySelector("#someElementId"); lock(targetElement) unlock(targetElement) 复制代码
tips: PC端不须要targetElement, 不传targetElement也不想要控制台提示能够传
null
import { lock, unlock } from 'tua-body-scroll-lock' lock() unlock() 复制代码