一直以来我的脑子里有一种执念(大约是2016年开始的),就是移动端无法做局部滚动,即对一个 div 设置
overflow: scroll
是无法滚动,所以才有了像 iScroll 、 Better-scroll 这样的库,但现在已经是 9012 年了,我发现移动端局部 滚动已经支持的很好了
问题介绍
最近碰到一个这样的需求,如下图所示:一个列表左侧边栏固定,右边内容部分可以滚动,同时上测标题栏可以吸顶
想法:
- 将整个区块分为上下两部分,上侧可以在吸顶的时候做 fixed 处理,然后每个区块再分为左右两部分,用 flex 布局,左侧固定宽度,右侧
flex: 1
占据剩余宽度。 - 右侧滚动区域可以用
better-scroll
做滚动处理,然后由于吸顶部分和内容分开,所以需要实例化两个BScroll
实例。然后当任意一个实例滚动时需要监听其scroll
事件,让另一个实例也滚动到 相应的scrollLeft
位置,在ios、安卓浏览器上都可以很完美的运行。但由于我们是hybird开发模式,拿到native上运行就有问题了(如图所示,我们的页面是嵌在新闻、赛程、球员、数据...
下的,每个tab就是一个webview,tab之间支持手势左滑右滑,这个时候用better-scroll滚动时,就会触发native的slider事件
,tab就被切换掉了,导致内容无法被滑动查看,后期找native开发人员请教下是怎么处理slider事件的)
解决方法
- 用原生
scroll
滚动 ,右侧元素设置overflow: scroll; -webkit-overflow-scrolling: touch; (ios惯性滚动)
,然后监听wrap
的scroll事件 - ios: 体验完美,在wrap范围内滚动不会触发
native slide
事件,并且有很好的边界回弹效果,出现滚动条, - 安卓:滚动也很流畅,但没有边界回弹效果并且当滚动到某一侧边界时依旧会触发
native slide
事件,不会出现滚动条
伪代码
- React 代码演示
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
45componentDidMount() {
// 标准模式和混杂模式的窗体滚动元素的获取
this.windowEl = document.scrollingElement || document.documentElement
this.titleTop = this.titleRef.offsetTop
window.addEventListener('scroll', () => this.wScroll())
}
// 吸顶处理
wScroll() {
if (this.windowEl.scrollTop == this.titleTop) {
this.titleRef.classList.add('fixed')
}
}
handleScroll = e => {
let left = e.target.scrollLeft
this.titleRef.scrollLeft = left
};
/**
监测捕获阶段的事件
onScroll 这都位于React合成事件,处于冒泡阶段
此处其实也可以绑定 wrap 的原生scroll事件
各种阶段事件触发的顺序:捕获 -> 冒泡 -> 原生 addEventListener('scroll')
*/
render() {
return (
<>
<div className="title" ref={ref=>this.titleRef=ref}>
<ul className="list">...</ul>
</div>
<div
className="wrap"
onScrollCapture={this.captureScroll}
>
<ul className="list">...</ul>
</div>
</>
);
}
------------
css
.title, .wrap {
overflow: scroll;
-webkit-overflow-scrolling: touch;
}