问题原因
FilterList需要解决的核心问题在于,IOS发生边界滚动
debounce行为时,尝试获取scrollLeft等滚动值会有延迟,同时在频繁快速触发debounce行为时,无法获取到scrollLeft等滚动值
*我们知道通过重写滚动,达到完全模拟滚动的效果一定能解决这个问题,但是我们还是希望能享受原生丝滑的滚动效果,没有丝毫延迟,有没有可能?
filterBar固定
固定filterBar有两种方式:
- 在达到临界条件时,将列表的第一项
fixed,同时通过margin或者padding撑开上顶部 filterBar单独抽离进行fixed定位,和滚动列表区域隔离开
方式1会有以下致命问题:
- 因为
filterBar需要被固定的第一项元素在filterBarwrap中,又bounce是基于当前有可滚动内容的盒子的容器边界,所以会发生一个诡异的现象,即边界无限高层级的bounce层覆盖容器内fixed定位的第一个元素的情况。总是被短暂覆盖,导致闪烁。 - 当
fixed定位元素的祖先容器存在滚动行为时,在快速滑动时会导致fixed定位丢失,发生跟随移动的问题。可通过[1]进行一定程度hack优化。
方式2因为fixed定位的filterBar和可能发生bounce的内容承载盒子相互隔离,所以不会存在这个问题。
问题处理
主要分X、Y轴两个场景进行考虑
以X轴场景为例,Y轴类似
1. X轴无需滑动,Y轴内容需要滑动,filterBar固定
此场景比较简单,适合小体量的简单列表;分离filterBar和content区域进行布局即可
2. X轴无需滑动,Y轴需要滑动,filterBar不需要固定
鸡肋场景,一体化布局即可
3. X轴需要滑动,Y轴需要滑动,filterBar固定
filterBar和content区域分离布局,使content基于Y轴的原生滚动不会在debounce发生时影响fixed定位和高层级覆盖问题contentX轴滚动内容,监听滚动事件,和filterBar做滚动同步,这里的同步需要使用A=B=scrollLeft的形式,使filterBar和contentX之间互相约束,尽可能的同步移动filterBar的滚动行为需要屏蔽掉,不然就需要考虑事件的动态绑定,因为同时绑定两个区域的滚动,且采用A=B=scrollLeft的形式,会导致多重赋值,发生视图抖动- X轴临界
debounce场景的处理:- 在X轴边界发生
debounce时,因为存在debounce特性导致的位移获取延迟甚至获取不到的问题,会导致filterBar位移同步脱节 - 解决这个问题需要增加手势操作,识别用户X+ X- Y+ Y-四个方向,同时配合
scrollLeft和scrollWidth和clientWidth之间的关系,检测是否到达边界 - 当到达边界以后,配合eventListener的passive特性,进行event.preventDefault()操作,屏蔽手势
- 但使用这个方法仍不是最佳效果,因为在边界发生
debounce的瞬间,是无法通过eventListener强制中断的,或者说,也没办法在发生debounce的瞬间即拿到scroll相关值,所以会发生细微的抖动,详细可以看demo效果,不过此效果也还可以了
- 在X轴边界发生
- 进一步优化用户疯狂在边界触发
debounce的行为:- 疯狂触发
debounce需要用户频繁的发生touch三部曲事件,可以在touchend发生时,激活一个fixed定位的高层级蒙板,阻断用户和真实滚动元素的交互,使频繁的debounce无法发生 - 亲测
debounce的效果结束大概在300ms以内,所以这样处理的代价是,需要屏蔽300ms手势,也即用户想在300ms内重复操作滚动成为了不可能
- 疯狂触发
模拟滚动
- 可以通过使用
betterScroll完全模拟X轴的滚动,组内亲测效果可以,只是X轴的滑动变得不丝滑。也难免,通过translate计算手势位移的方式,是很耗费性能的。