微信小程序自定義日曆組件及flex布局最後一行對齊問(wèn)題分析 - 新聞資(zī)訊 - 雲南小程序開發|雲南軟件開發|雲南網站(zhàn)建設-西山區知普網絡科技工作室

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不管是網站(zhàn),軟件還是小程序,都要直接或間接能為您産生價值,我們在追求其視覺表現的同時,更側重于功能的便捷,營銷的便利,運營的高效,讓網站(zhàn)成為營銷工具,讓軟件能切實提升企業(yè)内部管理水平和(hé)效率。優秀的程序為後期升級提供便捷的支持!

微信小程序自定義日曆組件及flex布局最後一行對齊問(wèn)題分析

發表時間:2020-10-19

發布人:葵宇科技

浏覽次數:59

最近為我開源的小項目:微信小程序擴展自定義組件庫(點擊去GitHub) 增加了一個(gè)新組件 —— 日曆組件。

在編寫過程中(zhōng),因為大家都知道,日曆組件是有固定行數和(hé)每一行的固定列數的(即使當前方塊内沒有值),所以結合小程序“數據優先”的特點,最合适的布局方式一定是flex了!

先說一下(xià)大緻思路(lù)(布局上),筆者将整個(gè)組件分為兩部分:分别是

  1. 頭部的當前日期(年月(yuè))顯示,以及左右兩側的切換按鈕
  2. 當前切換月(yuè)份的日期顯示

頭部的布局自不多說:一個(gè) display:flex; 加上 align-items:center; 居中(zhōng)簡直完美。
底部的日期顯示我是采用的“将整體分為六行,每一行七列”的布局方式 —— 因為一個(gè)月(yuè)最多31天,每一周最多7天,6X7=42,行數六行足夠使用。(而且現在基本上日曆都是6行7列的)

這樣的話我就給每一行設置相同的class,讓其再用flex規範子(zǐ)元素(子(zǐ)組件):

<view class="calendar_panel calendar_panel_two">
    <view class="calendar_box">
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    	<view class="weekday_label"></view>
    </view>
    <view class="calendar_box" wx:for="{{dateList}}" wx:for-item="week" style="{{index==0?'justify-content:flex-end':''}}">
     	 <view class="weekday_label wx:for="{{week}}">
      		<view class="" bindtap="selectDate" data-date="{{item}}">
      			{{item.date}}
      		</view>
      	</view>
    </view>
</view>
.calendar_panel{
    width: 100%;
    height: calc(100% - 56rpx);
}
.calendar_panel_two{
    display: flex;
    flex-direction: column;
    justify-content: space-around;
}
.calendar_box{
    width: 100%;
    background: #fff;
    overflow: hidden;
    display: flex;
    justify-content: space-around;
    height: calc(100% / 6);
    align-items: center;
}
.weekday_label{
    font-size: 27rpx;
    padding: 12rpx 0;
    display: flex;
    align-items: center;
    overflow: hidden;
}
.weekday_label>view{
    box-sizing: border-box;
    padding: 20%;
}
.select_icon{
    width: 30rpx;
    height: 30rpx;
}
.active_date{
    background: rgba(0,0,0,.12);
    color: rgba(0,0,0,.6);
    overflow: hidden;
    position: relative;
}
.active_dates{
    background: rgba(0,0,0,.1);
    color: rgba(0,0,0,.5);
    position: relative;
}
.active_dates::before{
    content: "今天";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    color: blue;
    font-size: 20rpx;
}

布局方完成,我滿心歡喜的按下(xià)ctrl+s,發現:
error

可(kě)以看到:控制每一行的類是 “calendar_box”,那麼毫無疑問(wèn),導緻出現如(rú)圖原因肯定是此類中(zhōng)有這樣一行代碼:

justify-content: space-around;

果不其然!


在本項目中(zhōng),我的解決方法很簡單:将這一行代碼去掉,那麼由此導緻的寬高問(wèn)題怎麼解決?
這個(gè)問(wèn)題,css給出了解決方案—— calc()
我将“每一行”的高度設為外部view的1/6:height:calc(100% / 6) (因為這是個(gè)組件,要用到其他地方,外部元素寬高不一定,所以要用百分比),每一行中(zhōng)列的寬度設為整行寬度的1/7:width:calc(100% / 7)
根據CSS文(wén)檔流的特點,這些元素在一行中(zhōng)就會一個(gè)接一個(gè)的排列,賊好看的那種~(去這裡)

答疑:
文(wén)章發出後有人留言問(wèn)“為啥不全部設置calc(100% / 6)然後用flex換行?”,emmmmmmm沒這個(gè)必要吧,這不是看個(gè)人喜好嗎,嘿嘿。先不說這裡我是采用的“周幾和(hé)日期父元素同一個(gè)class,在裡面隻控制和(hé)‘整行’相關(guān)的屬性值”的策略;其實這裡也是一個(gè)語義化:一周有七個(gè)日期,那一行就放七個(gè)元素,之間互不影響 —— 你(nǐ)如(rú)果去GitHub看源碼的話就會發現:在JS渲染日期時我就有意将每一行之間(也就是每一周)“隔離(lí)操作、單獨渲染”。

當然,你(nǐ)也可(kě)以如(rú)代碼中(zhōng)判斷index==0(第一行)一樣去判斷:

style="{{index==5?'justify-content:flex-start':''}}"

不過就顯得有點“多此一舉”了。

有了calc等css3函數的“加盟”,可(kě)以預見這種純‘原生’的解決方式将會越來越多的被使用到各種場景。

sucess

剛才說了,這個(gè)案例中(zhōng)的行列數是固定的 —— 這并不少(shǎo)見!那麼,除了本文(wén)提出的解決方法,還能怎麼做?

動(dòng)态改變最後一個(gè)元素的寬度

我們都知道,flex布局中(zhōng)還有一個(gè)比較著名的概念就是 flex: 1;flex: auto;)了,他能動(dòng)态“填滿”剩餘空間,那麼我們再子(zǐ)元素同級位置再加一個(gè)元素,對他設置最小寬度為子(zǐ)元素相同寬度,并且margin和(hé)子(zǐ)元素一緻:

<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <i class="lists"></i>
</div>
.container {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}
.list {
    width:100px;
    height:100px;
    background-color: skyblue;
    margin: 10px;
}
i.lists{
   min-width:100px;
   margin: 0 10px;
}

這個(gè)方法和(hé)下(xià)一個(gè)問(wèn)題的第一種方法類似,但要簡單很多!

警告!
經過有讀者留言提醒,這種方法确實不準确(感謝@李奕威(微信用戶)),當時筆者測試的時候沒有考慮到所有情況而且測試用class為list的div的個(gè)數有些取巧造成了這一現象。後經過多次測試發現:這種方法受min-width的影響在一些特殊情況下(xià)可(kě)行(比如(rú):list個(gè)數為7且一行最多四個(gè)(每行列數可(kě)小于4)時是可(kě)以的,但這種規律不是絕對的) —— 如(rú)果不是flex,它将會呈現和(hé)為最後一個(gè)元素添加“margin-right:auto”一樣的效果!
所以,建議跳過這種方法,我會再探索其相關(guān)實踐應用。

根據個(gè)數最後一個(gè)元素動(dòng)态margin

簡單來說就是:單獨設置最後一行的最後一個(gè)元素,控制其margin-right
由于每一列的數目都是固定的,因此,我們可(kě)以計算出不同個(gè)數列表應當多大的margin值才能保證完全左對齊。
例如(rú),假設每行4個(gè)元素,結果最後一行隻有3個(gè)元素,則最後一個(gè)元素的margin-right大小是“列表寬度+間隙大小”的話,那最後3個(gè)元素也是可(kě)以完美左對齊的。
然後,借助樹(shù)結構僞類數量匹配技術(shù),我們可(kě)以知道最後一行有幾個(gè)元素。
例如(rú):

  1. .list:last-child:nth-child(4n - 1)說明最後一行,要麼3個(gè)元素,要麼7個(gè)元素……
  2. .list:last-child:nth-child(4n - 2)說明最後一行,要麼2個(gè)元素,要麼6個(gè)元素……
.container {
    display: flex;
    /* 兩端對齊 */
    justify-content: space-between;
    flex-wrap: wrap;
}
.list {
    width: 24%; height: 100px;
    background-color: skyblue;
    margin-top: 15px;
}
/* 如(rú)果最後一行是3個(gè)元素 */
.list:last-child:nth-child(4n - 1) {
    margin-right: calc(24% + 4% / 3);
}
/* 如(rú)果最後一行是2個(gè)元素 */
.list:last-child:nth-child(4n - 2) {
    margin-right: calc(48% + 8% / 3);
}

那麼,如(rú)果每一行的列數是不固定的呢(ne)?

這個(gè)問(wèn)題的解法有很多種,其中(zhōng)筆者最“推崇”的是——用空白元素占位!
使用足夠的空白标簽進行填充占位:具體的占位數量是由最多列數的個(gè)數決定的,例如(rú)這個(gè)布局最多7列,那我們可(kě)以使用7個(gè)空白标簽進行填充占位,最多10列,那我們需要使用10個(gè)空白标簽。

<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <i></i><i></i><i></i><i></i><i></i>
</div>

這種方法的缺點(同時也是優點)就是:占位的 <i> 元素寬度和(hé)margin設置必須和(hé)列表父元素一樣即可(kě)!

.container {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    margin-right: -10px;
}
.container .list {
    width: 100px; 
    height:100px;
    background-color: skyblue;
    margin: 15px 10px 0 0;
}
/* 和(hé)列表一樣的寬度和(hé)margin值 */
.container > i {
    width: 100px;
    margin-right: 10px;
}

這裡要左對齊,則設置i的margin-right;同樣的如(rú)果右對齊,則需設置margin-left。

還有一種目前被很多人接受的方法就是曾經風靡的grid布局 —— 它有天然的單側對其和(hé)方塊間隙,對熟悉grid的人來說,本文(wén)這個(gè)問(wèn)題幾乎不會出現:

/** html代碼 */
<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
</div>

/** CSS代碼 */
.container {
    display: grid;
    justify-content: space-between;
    grid-template-columns: repeat(auto-fill, 100px);
    grid-gap: 10px;
}
.list {
    width: 100px; 
    height:100px;
    background-color: skyblue;
    margin-top: 5px;
}

答疑:
我看到文(wén)章發出後有人留言問(wèn)“如(rú)果像這種模塊分布,但列數不固定且是根據可(kě)視化窗口變化決定一列放多少(shǎo)個(gè),但是要每個(gè)方塊的間距都是一樣的”?這種問(wèn)題其實很簡單:上面這個(gè)用grid布局的代碼如(rú)果将 justify-content: space-between; 換為 justify-content: space-around; 就可(kě)以了。。。(雖然也會有間距變化,但是在可(kě)接受範圍,‘空白’不會顯得突兀)
現在的問(wèn)題是因為“space-between”是按照“最兩側的貼近父容器(qì)邊緣”的方法排版的,也就是說類似“兩邊的兩個(gè)貼着邊,剩下(xià)的幾個(gè)瓜分中(zhōng)間的空間,每往裡一層還是按這樣的方式”,也就造成了響應式變化時由于一行内個(gè)數變化中(zhōng)間會有一大片空白的效果。


最後再介紹一下(xià)這個(gè)組件:它在調用時接收兩個(gè)參數——他們是兩個(gè)event函數,你(nǐ)需要監聽他們,你(nǐ)可(kě)以得到:剛顯示組件時的當前日期/星期幾和(hé)你(nǐ)點擊選中(zhōng)日期時選中(zhōng)的年月(yuè)日和(hé)星期幾
back
2020-09-28更新
你(nǐ)可(kě)以在調用組件時傳入一個(gè)數組參數 dateTimes ,它的作用:标記哪一天的事件。它的格式如(rú):
piece
他将顯示如(rú)下(xià):
show


結尾:

以後可(kě)能為組件增加什麼功能就把布局方式更新了,到時候再回來補。

臨近國慶學校(xiào)沒啥課,電腦放工作室沒帶回,室友電腦有點不會用,就到這吧。中(zhōng)秋&國慶快樂(yuè),嘿嘿!

相關(guān)案例查看更多