在微信小程序开发中,会经常遇到“滚动穿透”的问题,就是当在弹窗或遮罩层上滚动时,下面的页面也会滚动,导致用户体验下降。这在我司也算是一个大 Bug,所以必须解决。
页面滚动,那禁止滚动就行,问题就是怎么禁用。一般两种方式:
-
全局禁用 page 的滚动,page 是小程序所有页面的上层,设置
overflow: hidden;
后可以禁止所有页面的超过滚动。但是问题也很明显,不支持动态设置,如果禁用了,那么所有页面都会受影响需要改动,而且可能会影响组件中的滚动。所以这个方案不可用。 -
给当前页面添加唯一容器,设置
overflow: auto;height:100vh;
,当弹窗或者遮罩显示时,设置overflow: hidden;
,此时可实现动态禁止页面滚动。但还是有限制,一些页面可能希望保持原生滚动,可以方便实现上拉加载等功能,而不是限制为固定高度,自己控制滚动过程。再一个就是此方案还需要设置disableScroll:true
,禁用bounce效果,不然页面还是会上下滚动,只是没有滚动条而已。
本来第二种方案已经是唯一解,只是改动一点就行,但是直到我看到 page-meta
组件,才发现这才是最优解。
关于对 page-meta
的说明,可以看官方文档:page-meta。其实文档说的也是一笔带过,page-meta
总结就是一个页面级别的配置节点,它只能是页面内的第一个节点,可以配置一些原本只能在 pages.json
中配置的属性,一定程度上可以替代 pages.json
。
而它有一个属性是 page-style
,用于配置页面根节点样式,其实就是设置全局的 page
样式,但是这里可以动态设置,并且在当前页面优先级更高。所以可以在弹窗或遮罩显示时,设置 page-style="overflow: hidden;"
,隐藏时设置 page-style="overflow: auto;"
,即可实现动态禁止页面滚动,这就解决了上面第一种方案的局限性。
所以最后,我只用了一行代码就解决了“滚动穿透”问题:
<page-meta :page-style="`overflow: ${isPopupShow ? 'hidden' : 'auto'}`" />
因为使用的 uniapp 开发,所以用的 vue 语法,要注意此节点一定要是页面的第一个节点,否则无效。