微信小程序自定義日曆組件及flex布局最後一行對齊問題分析 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

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

知識

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

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

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

發表時(shí)間:2020-10-19

發布人(rén):融晨科技

浏覽次數:95

最近爲(wéi / wèi)我開源的(de)小項目:微信小程序擴展自定義組件庫(點擊去GitHub) 增加了(le/liǎo)一個(gè)新組件 —— 日曆組件。

在(zài)編寫過程中,因爲(wéi / wèi)大(dà)家都知道(dào),日曆組件是(shì)有固定行數和(hé / huò)每一行的(de)固定列數的(de)(即使當前方塊内沒有值),所以(yǐ)結合小程序“數據優先”的(de)特點,最合适的(de)布局方式一定是(shì)flex了(le/liǎo)!

先說(shuō)一下大(dà)緻思路(布局上(shàng)),筆者将整個(gè)組件分爲(wéi / wèi)兩部分:分别是(shì)

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

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

這(zhè)樣的(de)話我就(jiù)給每一行設置相同的(de)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;
}

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

可以(yǐ)看到(dào):控制每一行的(de)類是(shì) “calendar_box”,那麽毫無疑問,導緻出(chū)現如圖原因肯定是(shì)此類中有這(zhè)樣一行代碼:

justify-content: space-around;

果不(bù)其然!


在(zài)本項目中,我的(de)解決方法很簡單:将這(zhè)一行代碼去掉,那麽由此導緻的(de)寬高問題怎麽解決?
這(zhè)個(gè)問題,css給出(chū)了(le/liǎo)解決方案—— calc()
我将“每一行”的(de)高度設爲(wéi / wèi)外部view的(de)1/6:height:calc(100% / 6) (因爲(wéi / wèi)這(zhè)是(shì)個(gè)組件,要(yào / yāo)用到(dào)其他(tā)地(dì / de)方,外部元素寬高不(bù)一定,所以(yǐ)要(yào / yāo)用百分比),每一行中列的(de)寬度設爲(wéi / wèi)整行寬度的(de)1/7:width:calc(100% / 7)
根據CSS文檔流的(de)特點,這(zhè)些元素在(zài)一行中就(jiù)會一個(gè)接一個(gè)的(de)排列,賊好看的(de)那種~(去這(zhè)裏)

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

當然,你也(yě)可以(yǐ)如代碼中判斷index==0(第一行)一樣去判斷:

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

不(bù)過就(jiù)顯得有點“多此一舉”了(le/liǎo)。

有了(le/liǎo)calc等css3函數的(de)“加盟”,可以(yǐ)預見這(zhè)種純‘原生’的(de)解決方式将會越來(lái)越多的(de)被使用到(dào)各種場景。

sucess

剛才說(shuō)了(le/liǎo),這(zhè)個(gè)案例中的(de)行列數是(shì)固定的(de) —— 這(zhè)并不(bù)少見!那麽,除了(le/liǎo)本文提出(chū)的(de)解決方法,還能怎麽做?

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

我們都知道(dào),flex布局中還有一個(gè)比較著名的(de)概念就(jiù)是(shì) flex: 1;flex: auto;)了(le/liǎo),他(tā)能動态“填滿”剩餘空間,那麽我們再子(zǐ)元素同級位置再加一個(gè)元素,對他(tā)設置最小寬度爲(wéi / wèi)子(zǐ)元素相同寬度,并且margin和(hé / huò)子(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;
}

這(zhè)個(gè)方法和(hé / huò)下一個(gè)問題的(de)第一種方法類似,但要(yào / yāo)簡單很多!

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

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

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

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

那麽,如果每一行的(de)列數是(shì)不(bù)固定的(de)呢?

這(zhè)個(gè)問題的(de)解法有很多種,其中筆者最“推崇”的(de)是(shì)——用空白元素占位!
使用足夠的(de)空白标簽進行填充占位:具體的(de)占位數量是(shì)由最多列數的(de)個(gè)數決定的(de),例如這(zhè)個(gè)布局最多7列,那我們可以(yǐ)使用7個(gè)空白标簽進行填充占位,最多10列,那我們需要(yào / yāo)使用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>

這(zhè)種方法的(de)缺點(同時(shí)也(yě)是(shì)優點)就(jiù)是(shì):占位的(de) <i> 元素寬度和(hé / huò)margin設置必須和(hé / huò)列表父元素一樣即可!

.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é / huò)列表一樣的(de)寬度和(hé / huò)margin值 */
.container > i {
    width: 100px;
    margin-right: 10px;
}

這(zhè)裏要(yào / yāo)左對齊,則設置i的(de)margin-right;同樣的(de)如果右對齊,則需設置margin-left。

還有一種目前被很多人(rén)接受的(de)方法就(jiù)是(shì)曾經風靡的(de)grid布局 —— 它有天然的(de)單側對其和(hé / huò)方塊間隙,對熟悉grid的(de)人(rén)來(lái)說(shuō),本文這(zhè)個(gè)問題幾乎不(bù)會出(chū)現:

/** 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;
}

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


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


結尾:

以(yǐ)後可能爲(wéi / wèi)組件增加什麽功能就(jiù)把布局方式更新了(le/liǎo),到(dào)時(shí)候再回來(lái)補。

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

相關案例查看更多