仿寫美團酒店日期選擇元件(小程式、React-Native)

stupidWall發表於2018-12-05

日期選擇

在哪

美團首頁 - 酒店住宿 - 日期選擇

美團上

美團小程式 & 美團App
仿寫美團酒店日期選擇元件(小程式、React-Native) 仿寫美團酒店日期選擇元件(小程式、React-Native)

我的DEMO效果

小程式(原生) & IOS(RN) & Android(RN)
仿寫美團酒店日期選擇元件(小程式、React-Native) 仿寫美團酒店日期選擇元件(小程式、React-Native) 仿寫美團酒店日期選擇元件(小程式、React-Native)

為啥寫

這幾天沒那麼忙,偶然瞄到美團這個元件,覺得很舒服,就想寫寫

美團小程式這功能估計很可能是mpvue寫的,我這裡使用小程式原生的元件去寫

美團App上的這個元件,我這裡用React-Native去寫

選擇器

小程式這一塊,是使用一個頁面去完成這個選擇的動作,而在App上的表現,是從底部彈出來的,好奇的我還去看了美團移動端頁面這個元件的表現,也有一些差異。 整體上來說,功能是一樣的,選日期,入店-離店日期。

咋寫的

  • 日曆怎麼生成?
問題拆分:
1. 怎麼獲取今天是星期幾?
2. 當前月份1號是星期幾?
3. 怎麼獲取上個月多餘出來的,要顯示在當前月置灰狀態的日期?
4. 上個月多餘的日期,怎麼控制有些要顯示出來,有些用不上?
5. 怎麼獲取到本月所有日期?
複製程式碼
使用moment.js日期處理庫
獲取今天是星期幾
# 若星期一則返回1, 即可能的值是[1,2,3,4,5,6,7]
moment().format('E')
複製程式碼
獲取這個月1號的日期物件和1號是星期幾
# 比如今天是12.05號,星期三
const m1 = moment().startOf('month')
const w1 = m1.format('E')
複製程式碼
獲取上個月多餘的日期陣列

獲取19年02月,上個月多餘的日期,即如下圖紅色日期

仿寫美團酒店日期選擇元件(小程式、React-Native)

其中從左到右分別為

['日', '一', '二', '三', '四', '五', '六']
複製程式碼

1號星期5,我知道,那這周的星期天,也就是這周的第一天的日期是可以推算出來的。

既然1號是星期五,那週日到週五,已經過了5天, 1號日期往後倒推5天就是週日那天的日期

firstDayTime.subtract(5, 'days')
複製程式碼

從而獲取到27 - 31號5天的一個日期陣列

同樣的思路, 19年02年月最後一行空缺的日期,也能算出來

仿寫美團酒店日期選擇元件(小程式、React-Native)

那也就是說,我每一個月的日期皮膚,都是完整的矩形,不存在空缺,把空缺的問題轉化為,怎麼去隱藏非本月的日期的顯示?

注意並非所有這個月1號之前的日期都是不可見的狀態,例如下圖

仿寫美團酒店日期選擇元件(小程式、React-Native)

12月1號是不可見,也不需要顯示的, 但2,3,4號是需要可見置灰狀態的, 我們發現這種情況下,無非就是當前一週裡,有過去了的日期,同時當月的1號也在這周裡面,根據這樣的條件,是不難去做出判斷的

當本月日曆列表出來後,那下一個月,下下個月的就變得簡單了,因為當前月的情況會更多一些,未來月份的情況是固定的

今天、明天、後天

App上體驗好一些,今、明、後天是直接標出的

const DAY_MAP = {
  [moment().format(FORMAT_TYPE)]: '今天',
  [moment().add(1, 'days').format(FORMAT_TYPE)]: '明天',
  [moment().add(2, 'days').format(FORMAT_TYPE)]: '後天'
}
...
!!DAY_MAP[formatDay] ? DAY_MAP[formatDay] : date
...
複製程式碼

佈局

flex佈局

這裡碰到一個問題,給每一個螢幕寬度一個七等分的處理,即每一個日期小框框寬度都是:(螢幕寬度 / 7)

750 / 7 
// 107.14285714285714
複製程式碼

當每一個小框框都以這個寬度佈局的時候, 肯定會有精度問題, 導致螢幕寬度沒有完整鋪滿,還有一點小縫隙的空間,這小縫隙是每一個小框框誤差累積出來的總和。

解決方法, 可以不使用flex-wrap:wrap, 不換行,然後一行全鋪滿flex:1, 這樣的話需要把陣列切割, 分行渲染。 如果要換行的話,可以簡單粗暴的判斷第七個小框框,給他一個flex:1, 也就是 (index + 1) % 7 == 0的時候

可供選擇的日期

我看美團小程式和App上都一樣, App上差不多半年日期可選,小程式上差不多是2個月,具體的演算法不太清楚。 我這裡是寫死的。

React-Native上

react-native-vector-icons

其中有一個關閉的圖示, 使用了react-native-vector-icons

react-native-animatable

彈起的動畫使用了react-native-animatable, 也可以自己寫這個過渡的動畫, 之前我已經安裝了這個動畫元件,也想著試用下

冒泡問題

app上元件彈出來後,點選陰影區域是可以關閉的,點選日期區域不會關閉的,RN上沒有冒泡機制配置,我這裡是通過給可見陰影區域加上TouchableOpacity元件覆蓋,加上專屬的Press事件。

其實發現是可以用一個TouchableOpacity元件在父標籤與子標籤之間再隔一層,達到不冒泡的效果。

ScrollView

如果使用TouchableOpacity元件包裹ScrollView元件,ScrollView會有問題,什麼問題,滾不了

SectionList

使用了這個元件完成日期列表分類,同時在IOS下有一個效果,滾動到頂部時,header粘連在螢幕的頂端,stickySectionHeadersEnabled屬性,預設true

計算選取了多少晚

使用moment.js方法

eMoment.diff(sMonent, 'days')
複製程式碼

問題

  • App上日期上的節假日未實現
  • App上‘請選擇離店日期’的提示會出現被header蓋住的情況,RN上沒有zIndex設定,規律是後面的元件層級高於前面的元件。 這裡使用了secondlist元件造成

原始碼

歡迎Star!!!!

相關文章