评论

如何彻底解决小程序滚动穿透问题

解决微信小程序滚动穿透的终极方案。

背景

俗话说,产品设计有三宝:弹窗、浮层加引导。可见“弹窗”在产品设计中的重要性。对于前端开发者来说,实现一个基础的模态框(Modal)并不难,可一旦模态框内部出现可滚动内容,各种意想不到的问题就会接踵而至——其中最为典型的,就是“滚动穿透”。

什么是滚动穿透?

滚动穿透指的是:当我们在顶层弹窗中执行滑动操作时,实际滚动的是底层页面的内容。这种体验非常影响交互,也常让用户感到困惑。

解决方案分析

解决滚动穿透的思路通常有两种:改变顶层或改变底层。

1. 改变顶层(不推荐)

一种自然的想法是阻止顶层的事件继续传播。例如,给遮罩层(蒙层)绑定 catchtouchmove 事件。但这种方法在部分场景下并不生效,因此并不是一个可靠的通用方案。

2. 改变底层(推荐)

既然问题是底层内容跟随滚动,那么只要在弹窗打开时禁止底层页面滚动,问题就迎刃而解。

具体实现方案

🟡 不成熟的方案

  • 将底层页面的最外层 view 设置为 position: fixed,但这会导致页面滚动位置丢失,回到顶部。

  • 另一种方式是:在打开弹窗前记录当前滚动位置,关闭弹窗后使用 wx.pageScrollTo 滚动回原位置。这种方法实现较为繁琐,且体验不够流畅。

✅ 成熟的方案

方案一:使用 page-meta 组件

通过微信小程序提供的 page-meta 组件,我们可以直接控制页面根容器的样式,类似于在 H5 中设置 body { overflow: hidden; }。

我们可以动态设置 overflow 属性为 hidden 或 auto,来控制页面是否可滚动。

方案二:使用 wx.setPageStyle 方法

这是一个更灵活的 API,特别适合在组件内部(如封装好的弹窗组件)使用,无需额外编写 page-meta 结构。

wx.setPageStyle({
  style: {
    overflow: 'hidden' // 或 'auto'
  }
})

代码示例

这里提供一个可供测试的代码片段,帮助你快速上手:

👉 点击查看代码片段

拓展:支付宝小程序的情况

支付宝小程序虽然也支持 page-meta 组件,但由于其 WebView 内核限制(版本 69),设置 overflow: hidden 并不能完全阻止底层滚动。

支付宝团队为此专门提供了新的 API:my.setPageScrollable,用于精确控制页面是否可滚动。

my.setPageScrollable({
  scrollable: false,
  success: (res) => console.log(res),
  fail: (err) => console.log(err)
})

更新(2025.06.18)

该 API 已正式开放。不过目前测试发现:在 安卓端 设置禁止滚动后,弹窗内的可滚动区域也会被一并禁止;iOS 端 则表现正常,仅底层页面被锁定。

原因分析:

安卓与 iOS 在滚动禁止的层级控制上存在系统级差异:

  • 安卓 采用 Webview 级别的滚动限制,生效时整个页面(包括所有弹层)均不可滚动;
  • iOS 采用组件级控制,能智能区分层级,仅锁定底层页面而保持弹窗内部可滚动。
最后一次编辑于  11-13  
点赞 52
收藏
评论

22 个评论

  • 惬意
    惬意
    2024-07-19

    我就发现不管什么东西用到极致就会发现他的bug,完事官方还不给解决

    2024-07-19
    赞同 2
    回复
  • 小刘
    小刘
    2021-12-13

    跟 web 里面的 Helmet 组件有点儿类似,可以用来修改 page-meta 信息。

    2021-12-13
    赞同 2
    回复
  • 2021-10-19

    page-meta 组件在 iPhone8 上无效,大佬们有遇到这种兼容问题吗?

    2021-10-19
    赞同 1
    回复 19
    • 胃里养了只霸王龙
      胃里养了只霸王龙
      2021-10-20
      查看下你的微信客户端版本是多少,再看对应的基础库是多少。这个组件有最低基础库限制的
      2021-10-20
      1
      回复
    • 2021-10-20回复胃里养了只霸王龙
      好的,我看下,感谢回复。
      2021-10-20
      回复
    • 2021-10-20回复胃里养了只霸王龙
      手机微信升级到最新版本8.0.15,调试基础库为2.20.0。还是没生效
      2021-10-20
      回复
    • 胃里养了只霸王龙
      胃里养了只霸王龙
      2021-10-20回复
      提供代码片段看下。我看下你是不是写错了。。。
      2021-10-20
      回复
    • 2021-10-20回复胃里养了只霸王龙
      2021-10-20
      回复
    查看更多(14)
  • yimi🌸
    yimi🌸
    2021-10-15

    弹窗弹出时,直接把底部的scroll-view的scroll-y设置为false,就可以阻止底层滚动了呀,不需要用这个page-meta吧

    2021-10-15
    赞同 1
    回复 2
    • 胃里养了只霸王龙
      胃里养了只霸王龙
      2021-10-15
      底部内容超出一屏。弹窗内有滚动会导致滚动穿透。而这个组件的作用跟 h5的控制body设置为overflow hidden控制底部不可滚动 是一样的原理。
      2021-10-15
      回复
    • yimi🌸
      yimi🌸
      2021-10-18回复胃里养了只霸王龙
      哦,我知道了,我以为最外层结构是scroll-view,没看清。这个的确是最佳方法👍
      2021-10-18
      回复
  • 困难
    困难
    2021-10-08

    感谢大佬。之前用catchtouchmove解决,后来弹窗变复杂就突然不好使了。。这个方法确实简单快捷

    2021-10-08
    赞同 1
    回复
  • 悦己
    悦己
    2021-07-15

    麻烦问下pageMeta在taro中怎么使用啊?

    2021-07-15
    赞同 1
    回复 3
    • 夜 惊 魂
      夜 惊 魂
      2021-08-03
      请问你解决了嘛😂
      2021-08-03
      回复
    • Gavin
      Gavin
      2021-08-24
      Taro有个方法你可以看看
      2021-08-24
      1
      回复
    • 东昇鸿旭
      东昇鸿旭
      发表于移动端
      2022-03-10回复Gavin
      、:-:
      2022-03-10
      回复
  • 陈关羽
    陈关羽
    2021-05-31

    老哥 这个方法很稳

    2021-05-31
    赞同 1
    回复
  • 来一间
    来一间
    2021-05-14

    https://developers.weixin.qq.com/community/develop/article/doc/000e40918dc420f5f61c2001a56013,这一篇写得特别详细,楼主也可以看看!

    2021-05-14
    赞同 1
    回复 4
    • HGP
      HGP
      2021-05-19
      这个链接是广告,然后这个层主是s13
      2021-05-19
      25
      回复
    • 🐸
      🐸
      2022-09-19回复HGP
      必须登录给你个赞
      2022-09-19
      回复
    • 骑着毛驴逗你玩儿
      骑着毛驴逗你玩儿
      2024-03-27
      拉出去弹蛋蛋 10 分钟...
      2024-03-27
      回复
    • 哄哄
      哄哄
      2024-12-03
      傻13 祝你的公司早日倒闭,老板死刑,员工无期
      2024-12-03
      回复
  • waterbang
    waterbang
    07-15

    uni 解决方案:<scroll-view class="select-list" scroll-y @touchmove.stop>


    07-15
    赞同
    回复 2
    • 一叶知秋
      一叶知秋
      08-11
      如果不是scroll-view可以用这个方案解决吗?
      08-11
      回复
    • waterbang
      waterbang
      08-11回复一叶知秋
      没试过,你可以定位看看你的真正滚动元素是什么,禁用其滚动
      08-11
      回复
  • 起风了
    起风了
    2024-12-05

    支付宝怎么操作?没在支付宝文档找到disableScroll 这个api

    2024-12-05
    赞同
    回复 1
    • 胃里养了只霸王龙
      胃里养了只霸王龙
      2024-12-05
      支付宝 view上有,但是无法阻止,我找他们的开发加了个api,然后目前还在封装到appx基础库里。
      方法名叫:my.setPageScrollable()  目前还没上线。
      2024-12-05
      回复

正在加载...

登录 后发表内容