抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

uni-app 编译到支付宝小程序,滚动穿透问题解决
通用解决,解决了弹窗和根组件同时可以滚动,但是只想滚动弹窗而不想根组件跟着滚动的情况

问题

因为在做 uniapp 编译到支付宝小程序,用的人少,网上没查到现成的解决方案
现有解决方案多用到浏览器 api,阻止冒泡,支付宝小程序真没有,现有的 api 我试了没用

要解决的问题是,经典滚动穿透问题
弹窗和根组件同时可以混动,因为滚动穿透的存在,滚动弹窗下面的根组件一并会被滚动
想要实现的是只弹窗滚动,下面的根组件不动。

解决方案

思路

在弹窗出来后,记录根组件滚动位置,然后给根组件设置成 position:fixed 状态
弹窗解除后,从 fixed 状态恢复,并根据记录的滚动位置,回到此前位置

可以说是相当粗暴,啥穿透,啥冒泡,直接不管,看 fixed 划不划的动就完事了
所以说也通用,支付宝小程序都能用

示例

比如说简单结构如下,root 和 dialog 里面都有大量内容,都可以滚动

1
2
3
<div class="root" :style="rootFixed">
<div class="dialog"></div>
</div>

在 dialog 出来之后,获取 root 当前滚动位置,并且改成 fixed,fixed 的 top 设置成滚动位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 记录当前滚动位置
let currentScrollTop = 0;
// root的style
const rootFixed = ref('');
function saveCurrentScrollPosition() {
// 这是支付宝小程序获取dom的api
my.createSelectorQuery()
.selectViewport()
.scrollOffset((res: any) => {
currentScrollTop = res.scrollTop;
console.log(currentScrollTop);
// 设置根元素在滑动标题的时候fixed的位置
// 由于这个dom获取api是异步的,直接放回调函数里面赋值了
rootFixed.value = `position: fixed; top: -${currentScrollTop}px;`;
})
.exec(() => {});
}

最后在弹窗解除后,根据之前记录的位置,把根组件滚动回去

1
2
3
4
5
6
7
8
9
10
11
12
13
// 恢复滚动位置
async function resetScrollPosition() {
// 这里这么写是因为my.pageScrollTo操作顺序必须在设置完position: static之后。
// 其实我试了,await sleep(1)之后都能正常,但是直接写就不正常了。。。放promise后算了
await new Promise((r) => {
rootFixed.value = 'position: static';
r('');
});
my.pageScrollTo({
scrollTop: currentScrollTop,
duration: 0,
});
}

最后

俩垃圾平台,这么经典问题都没现成解决方案
哎,要怪只能怪自己一块选俩罕见平台,强强组合了属于是,坑 × 坑

评论