在做移动端的H5页面时,由于有些手机或浏览器自有的特性,整个页面具有下拉刷新功能。但如果我们的需求是下拉获取下一页的数据,不希望下拉刷新,但同时也想保留整个页面的正常上下滚动,该如何做呢?
尝试过禁用body上的touchmove事件,但是禁用后发现到整个页面都不能滑动了,所以转变思路。
实现要点
- 给body元素设置高度,并设置overflow: hidden (这是不触发浏览器自带下拉刷新的关键,但离开页面时,记得还原,不然会影响其他页面的正常滚动)
- 给滚动区域设置固定高度,并设置overflow: scroll
- 如果要求完美,比如iPhone11等全面屏手机,有些小可爱会把搜索栏设置在底部,这时候会遮挡到页面,如果要解决这个问题,可以给滚动div设置成固定定位 position: fixed;
上代码
/** 消息列表 */
const MessageList = () => {
const [_list, setList] = useState<Message[]>([])
const [_info, setInfo] = useStates<any>(INIT_DATA)
/** 记住上一次的高度 */
const [_lastHeight, setLastHeight] = useState<number>(0)
const ref = useRef<any>()
const onRefresh = () => {
return getList()
}
const getList = async () => {
try {
const { data } = await MessageService.getMessage({ message_system_type: "h5", page: _info.page })
if (!data || !data?.lists?.length) {
_info.showEmptyCard = true
setInfo(_info)
return
}
if (_info.page == 1) {
setList(data?.lists?.reverse())
} else {
setList(reverseAry(data?.lists))
}
_info.page = _info.page + 1
if (data?.lists?.length < 15) {
_info.disable = true
}
setInfo(_info)
// window.scrollTo(0, ref.current.offsetHeight - _lastHeight)
document.getElementById("sPage").scrollTo(0, ref.current.offsetHeight - _lastHeight) //因为我们是在父级div中滚动,所以控制滚动距离就不能用window了
setLastHeight(ref.current.offsetHeight)
} catch {}
}
/** 消息反转 */
const reverseAry = (ary: any[]) => {
const tempArr = [...ary]
tempArr.reverse()
const newArr = [...tempArr, ..._list]
return newArr
}
const wait = (ms: number) => new Promise((resolve: any) => setTimeout(() => resolve(), ms))
const init = autoLoading(async () => {
await getList()
await wait(400)
// window.scrollTo(0, ref.current?.offsetHeight)
document.getElementById("sPage").scrollTo(0, ref.current?.offsetHeight) //因为我们是在父级div中滚动,所以控制滚动距离就不能用window了
})
useEffect(() => {
init()
return () => {
INIT_DATA.page = 1
INIT_DATA.showEmptyCard = false
setInfo(INIT_DATA)
}
}, [])
useEffect(() => {
document.body.style.overflow = "hidden" //进入页面时给body添加行类样式 overflow:hidden
return () => {
document.body.style.overflow = "visible" //离开页面时给body还原 overflow 为默认值
}
}, [])
return (
<PullToRefresh disable={_info.disable} onRefresh={onRefresh}>
<Visible visible={_info.disable}>
<div className={styles.noMore}>- 没有更多消息了 -</div>
</Visible>
<Visible visible={!!_list?.length}>
<div className={styles.box} ref={ref}>
{_list?.map((item) => (
<MessageCard {...item} key={item.id} />
))}
</div>
</Visible>
<Visible visible={_info.showEmptyCard}>
<Empty />
</Visible>
</PullToRefresh>
)
}
export default MessageList