webview 和 React Native 中吸頂效果實現

作者 | 👽

來源 | Sharing

一、前言

在跨端開發中,離不開一些吸頂的互動場景,可以參考淘寶或是京東類電商 app 中一些 tab ,在整個容器滑動的過程中,吸頂效果非常的連貫和絲滑的,當然這些 tab 可能是用 native 開發的,但是跨端應用也能實現很不錯的吸頂效果,那麼今天我們就來研究一下跨端開發是如何實現吸頂的。

希望通過這篇文章,你將學習到:

  • webview 中吸頂的實現方式。

  • React Native 中吸頂方法,SectionList 是如何實現吸頂的。

二、webview 吸頂實現方式

在移動端開發中,webview 已經成為很重要的一部分,比如 app 中內嵌的 web 頁面,或者小程序的視圖載體,本質上都是 webview。

基於 webview 的混合開發模式非常受到歡迎,回到今天的主題上來,在 webview 中如何實現吸頂效果呢?

2.1 position :sticky

webview 本質上就是 web 應用,所以我們可以使用 css 屬性來做很多互動效果。如果說到吸頂效果,這裡首先想到的就是 position:sticky 粘性屬性。

position:sticky 是一個新的css3屬性,它的表現類似於 position:relative 和 position:fixed 的交集。

  • 在目標區域在螢幕中可見時,它的行為就像 position:relative;

  • 而當頁面滾動超出目標區域時,它的表現就像 position:fixed,它會固定在目標位置。

通過上面可以得出,如果實現吸頂效果,設置一個 css 屬性就能實現。

WechatIMG2225.jpeg

如上圖所示,圖中 head 部分是需要吸頂的內容,那麼把 head 加上 position:sticky 就可以了。

sticky 的缺點:

當然 sticky 也有一些缺點:

  • sticky 屬性存在兼容性。

  • sticky 和 absolute 定位屬性在 ios 上的表現不友好,在 scrollview 等視圖容器元件內部滾動時候,可能存在抖動的問題,這樣使用者體驗非常差。

2.2 scrollview

webview 還有一種實現吸頂的方法,就是通過 scrollview ,scrollview 是什麼?scrollview 是一個滾動的容器元件,web 中並沒有現成的 scrollview 元件,常見的 scrollview 元件主要存在小程序或者一些跨段解決方案中,比如 Taro 中的 Scrollview,這些元件並非是原生元件,都是在各個平臺底層基於原生的 DOM 元素和 EventListener 封裝的。

以微信小程序為例子,看一下 scroll-view 如何實現吸頂,這種方式主要是依靠計算的方式,來確定什麼時候元素應該吸頂了。因為 scroll-view 上有回呼函式 bindscroll ,可以實時的得到滾動的距離,使用滾動距離,可以推匯出吸頂臨界點。

通過上面可以推匯出 offsetTop === scrollTop 此時就是 current 吸頂的臨界點。當然在不同場景下,這個臨界點可以會有區別,但大體思路是不變的。

但是目前可能存在一些問題,就是如果我們繼續通過 position:absolute 來觸發吸頂的話,還會有 2.1 面臨的問題——在 scroll-view 中使用了定位產生抖動,那麼應該如何處理呢?

筆者在這裡推薦大家一種方法就是,用兩個吸頂模組,來模擬吸頂效果的實現:

  • 如上 current 是需要吸頂的元件,但是我們準備兩個狀態一樣的元件 current1 和 current2,current1 在 scroll-view 外部,用 fixed 定位,定位在容器頂部,current2 在 scroll-view 內部,不加任何定位效果。

  • 在正常情況下,不是吸頂情況下,current1 是隱藏狀態 ,current2 是顯示狀態。

  • 如果達到了吸頂的臨界點,那麼改變狀態,current1 變成顯示狀態,current2 變成隱藏狀態,這裡有一點需要注意,因為我們隱藏了 current2 如果不做處理,會讓下面元素頂上來,這裡處理的方案是通過一個元素佔位,如下面程式碼塊中 class=”hold” 元素,就是佔位元素。佔位元素的高度和 current2 高度相同。

用程式碼簡單描述一下過程:

wxml中:

js 中:

/* 處理滾動事件 */

handleScroll(event){

const { scrollTop } = event.detail

const { offsetTop,show }= this.data

const isCeiling = scrollTop === offsetTop

if(isCeiling !== show ){

/* 當吸頂狀態發生變化時 */

this.setData({

show:isCeiling

})

}

}

這種方式實現吸頂也有一些缺點,就是當快速滑動的時候,比如小程序,因為觸發吸頂調用 setData ,setData 底層會調用於 native 通訊的方法,這樣視圖上的更新會滯後,直觀上的感受就是置頂效果滯後。

三、React Native 中的吸頂方式

React Native 是跨端開發的一個解決方案,不同於 webview,webview 的渲染還是走 web 那一套,而 RN 這個一點就不同於 webview,採用了 Native 方式來渲染,所以就渲染性能上要優於 webview。

RN 中有很多中實現吸頂的方式,ScrollView ,FlatList ,和 SectionList 都能實現吸頂效果,

3.1 ScrollView 和 FlatList

ScrollView 和 FlatList 一般用於列表元件,兩者中有一個stickyHeaderIndices 可以輕鬆實現吸頂效果。

<ScrollView

stickyHeaderIndices={[0]}//第一個子元素即頭部元件,上滑時吸頂

/>

  • stickyHeaderIndices: 一個子視圖下標的陣列,用於決定哪些成員會在滾動之後固定在螢幕頂端。舉個例子,傳遞stickyHeaderIndices={[0]}會讓第一個成員固定在滾動視圖頂端。這個屬性不能和horizontal={true}一起使用。

但是筆者在工作中,用到吸頂的場景,並不是單單列表中的某一個元素,有可能是視圖中某一個 section 模組的頭部。

所以接下來重點介紹一個場景,就是通過 SectionList 來實現吸頂效果。

3.2 SectionList 介紹及如何實現吸頂效果

SectionList 是高性能的分組(section)列表元件,支持下面這些常用的功能:

  • 完全跨平臺。

  • 行元件顯示或隱藏時可配置回調事件。

  • 支持單獨的頭部元件。

  • 支持單獨的尾部元件。

  • 支持自定義行間分隔線。

  • 支持分組的頭部元件。

  • 支持分組的分隔線。

  • 支持多種資料來源結構

  • 支持下拉刷新。

  • 支持上拉載入。

SectionList 顧名思義,就是分 Section 模組的列表。SectionList 的吸頂效果也是得益於一個屬性——stickySectionHeadersEnabled。

當 stickySectionHeadersEnabled 為 true 的時候,當下一個 section 把它的前一個 section 的可視區推離螢幕的時候,讓這個 section 的 header 粘連在螢幕的頂端。這個屬性在 iOS 上是默認可用的,因為這是 iOS 的平臺規範。

WechatIMG2259.jpeg

如上我們期望 section2 的 current 模組吸頂,那麼當 section1 元素離開可視區域的時候,section2 的 current 就會吸頂了。這樣說,有的同學可能不明白,我們來看一下具體使用。

具體使用:

const defaultSections = [

{

data:[ name:'section1' ],

key:'section1',

},

{

data:[ name:'section2' ],

key:'section2',

},

]

function Index(){

//....省去一些邏輯

const renderContent = ({ item:{ name } }) => ( name === 'section1' ? : );

/* 當只有 section2 有頭部並且會吸頂 */

const renderHeader = ({ section:{ key } }) => (key === 'section2' && )

return <SectionList

sections={defaultSections} // section 的配置項

renderSectionHeader={renderHeader} // 分 section 渲染頭部

renderItem={renderContent} // 分 section 渲染主體內容

stickySectionHeadersEnabled // 設置吸頂狀態為 true

/>

}

  • 如上,可以通過 sections ,renderSectionHeader,renderItem 來自由的組合 SectionList 需要展現的 content 和 header,這樣會讓吸頂功能更加靈活。

四、總結

本文介紹了跨端開發中,webview 和 React Native 實現吸頂的主流方式,希望能給做此類功能的同學提供一個解決思路。

相關文章

React-Native 開發實用指南

React-Native 開發實用指南

【CSDN 編者按】本文主要介紹 React-Native 的實際使用經驗,對於想要快速入門的同學是有幫助的。 作者 | 佐玉 整體介紹 首...

React Native 開發真有那麼好?!

React Native 開發真有那麼好?!

整理 | 蘇宓 兜兜轉轉,不少開發者還是發現 React Native 的真相定律。 日前,國外知名聊天軟體 Discord 於官方部落格上...

為什麼我不使用 Next.js?

為什麼我不使用 Next.js?

【CSDN 編者按】Next.js是 Remix 的一個非常流行的替代品,本文作者想誠實地表達個人對 Next.js 的看法和使用體驗,並非...

Python 與 JavaScript 做比較公平嗎?

Python 與 JavaScript 做比較公平嗎?

在討論應該使用 Python 還是 JavaScript 構建項目時,一般我們都不會說只使用一種程式語言來構建所有的元件。 在現代軟體開發中...