小程序頁面滾動穿透
一、場景
- 在項目當中,基礎遇到這樣的需求
有一個長列表,或者其他可滾動展示的頁面,
在這個頁面會彈出一個Modal
層,如下:
貝殼找房的 的篩選欄
二、問題
如果這個彈框內容不可滾動,不會有太大問題;
但是當彈出內容是可以滾動的時候,就會有問題,
觸摸沒有滾動的區域會發現滾動可以穿透,會傳遞給下面的列表頁面,
三、解決辦法
程序員是面向Google編程的,找到了下面的解決辦法:
- 監聽彈框狀態,如果彈框展示就給列表 添加對應樣式
// isShowMask 彈框是否展示
<view class="dog-container {{isShowMask ? 'bottom-fixed' : ''}}"></view>
.bottom-fixed {
position: fixed;
left: 0;
top: 0;
overflow: hidden;
}
- 給遮罩層添加
catchtouchmove
的阻止
myCatchTouch: function () {
return;
}
<view wx:if="{{alert}}" catchtouchmove="myCatchTouch">
<template is="alert" data="{{alertData}}" />
</view>
這樣的話,底部的列表內容就不會出現溢出,也自然不會滾動,
::: warning
但是,這樣的做法有一個弊端,
不會去記錄我之前訪問的位置,也就是每次點開彈框,列表位置會歸零,體驗終歸是不好的。
:::
四、升級方案
於是我去翻了一些開源小程序UI的Demo,去試試看這種彈框類型的交互,
最後發現在Taro UI
中有一個組件,Float LayOu
,是沒有出現穿透的,列表位置也沒有發生改變,
- 於是,我翻了源碼,發現他是這樣寫的(有刪減):
// 重點A:阻止事件冒泡
handleTouchMove = (e) => {
e.stopPropagation()
}
render() {
return (
<View className='rootClass' onTouchMove={this.handleTouchMove}>
<!-- 遮罩層 -->
<View onClick={this.close} className='at-float-layout__overlay' />
<View className='at-float-layout__container layout'>
<View className='layout-body'>
<!-- 重點B: ScrollView(開啓scrollY)-->
<ScrollView
scrollY
scrollX={false}
className='layout-body__content'
>
{this.props.children}
</ScrollView>
</View>
</View>
</View>
)
}
- 思路解析:
i、首先,需要在自定義彈框的根元素,添加 onTouchMove
監聽,並阻止時間的冒泡
<View className='rootClass' onTouchMove={this.handleTouchMove}>
ii、但是,裏面的內容,就不能滾動了,那麼,可以使用 ScrollView
代替View
,並開啓Y軸的滾動
<ScrollView
scrollY
scrollX={false}
className='layout-body__content'
>
<!-- 內容區域-->
<!-- 內容區域-->
</ScrollView>
按照這樣的思路,我在項目裏面嘗試了下,果然奏效,這樣的方式更優雅體驗也更好。
筆者使用了Taro,但原理都是一樣的。
- 最終效果:
五、關於stopPropagation
簡單來說:
::: tip
JavaScript
中,冒泡和捕獲是事件流的兩種行爲,使用event.stopPropagation()可以起到阻止捕獲和冒泡階段中當前事件的進一步傳播。
而使用event.preventDefault()可以取消默認事件。
:::
事件流
事件流描述的是從頁面中接受事件的順序,分爲
-
IE的事件流是 事件冒泡流,
-
標準的瀏覽器事件流是 事件捕獲流。
好了,希望對大家有用,對事件流有興趣的可以自行Google
或者看下這片文章:JavaScript的事件流
Ending…