淺析微信小程序自定義日歷組件及flex布局最后一行對(duì)齊問題
最近為我開源的小項(xiàng)目:微信小程序擴(kuò)展自定義組件庫(點(diǎn)擊去GitHub) 增加了一個(gè)新組件 —— 日歷組件。
效果演示:
在編寫過程中,因?yàn)榇蠹叶贾?,日歷組件是有固定行數(shù)和每一行的固定列數(shù)的(即使當(dāng)前方塊內(nèi)沒有值),所以結(jié)合小程序“數(shù)據(jù)優(yōu)先”的特點(diǎn),最合適的布局方式一定是flex了!
先說一下大致思路(布局上),筆者將整個(gè)組件分為兩部分:分別是
- 頭部的當(dāng)前日期(年月)顯示,以及左右兩側(cè)的切換按鈕
- 當(dāng)前切換月份的日期顯示
頭部的布局自不多說:一個(gè) display:flex;
加上 align-items:center;
居中簡直完美。
底部的日期顯示我是采用的“將整體分為六行,每一行七列”的布局方式 —— 因?yàn)橐粋€(gè)月最多31天,每一周最多7天,6X7=42,行數(shù)六行足夠使用。(而且現(xiàn)在基本上日歷都是6行7列的)
這樣的話我就給每一行設(shè)置相同的class,讓其再用flex規(guī)范子元素(子組件):
<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; }
布局方完成,我滿心歡喜的按下ctrl+s,發(fā)現(xiàn):
可以看到:控制每一行的類是 “calendar_box”,那么毫無疑問,導(dǎo)致出現(xiàn)如圖原因肯定是此類中有這樣一行代碼:
justify-content: space-around;
果不其然!
在本項(xiàng)目中,我的解決方法很簡單:將這一行代碼去掉,那么由此導(dǎo)致的寬高問題怎么解決?
這個(gè)問題,css給出了解決方案—— calc()
!
我將“每一行”的高度設(shè)為外部view的1/6:height:calc(100% / 6)
(因?yàn)檫@是個(gè)組件,要用到其他地方,外部元素寬高不一定,所以要用百分比),每一行中列的寬度設(shè)為整行寬度的1/7:width:calc(100% / 7)
根據(jù)CSS文檔流的特點(diǎn),這些元素在一行中就會(huì)一個(gè)接一個(gè)的排列,賊好看的那種~(去這里)
答疑:
文章發(fā)出后有人留言問“為啥不全部設(shè)置calc(100% / 6)然后用flex換行?”,emmmmmmm沒這個(gè)必要吧,這不是看個(gè)人喜好嗎,嘿嘿。先不說這里我是采用的“周幾和日期父元素同一個(gè)class,在里面只控制和‘整行'相關(guān)的屬性值”的策略;其實(shí)這里也是一個(gè)語義化:一周有七個(gè)日期,那一行就放七個(gè)元素,之間互不影響 —— 你如果去GitHub看源碼的話就會(huì)發(fā)現(xiàn):在JS渲染日期時(shí)我就有意將每一行之間(也就是每一周)“隔離操作、單獨(dú)渲染”。
當(dāng)然,你也可以如代碼中判斷index==0(第一行)一樣去判斷:
style="{{index==5?'justify-content:flex-start':''}}"
不過就顯得有點(diǎn)“多此一舉”了。
有了calc等css3函數(shù)的“加盟”,可以預(yù)見這種純‘原生'的解決方式將會(huì)越來越多的被使用到各種場景。
剛才說了,這個(gè)案例中的行列數(shù)是固定的 —— 這并不少見!那么,除了本文提出的解決方法,還能怎么做?
動(dòng)態(tài)改變最后一個(gè)元素的寬度
我們都知道,flex布局中還有一個(gè)比較著名的概念就是 flex: 1;
(flex: auto;
)了,他能動(dòng)態(tài)“填滿”剩余空間,那么我們?cè)僮釉赝?jí)位置再加一個(gè)元素,對(duì)他設(shè)置最小寬度為子元素相同寬度,并且margin和子元素一致:
<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è)方法和下一個(gè)問題的第一種方法類似,但要簡單很多!
警告!
經(jīng)過有讀者留言提醒,這種方法確實(shí)不準(zhǔn)確(感謝@李奕威(微信用戶)),當(dāng)時(shí)筆者測(cè)試的時(shí)候沒有考慮到所有情況而且測(cè)試用class為list的div的個(gè)數(shù)有些取巧造成了這一現(xiàn)象。后經(jīng)過多次測(cè)試發(fā)現(xiàn):這種方法受min-width的影響在一些特殊情況下可行(比如:list個(gè)數(shù)為7且一行最多四個(gè)(每行列數(shù)可小于4)時(shí)是可以的,但這種規(guī)律不是絕對(duì)的) —— 如果不是flex,它將會(huì)呈現(xiàn)和為最后一個(gè)元素添加“margin-right:auto”一樣的效果!
所以,建議跳過這種方法,我會(huì)再探索其相關(guān)實(shí)踐應(yīng)用。
根據(jù)個(gè)數(shù)最后一個(gè)元素動(dòng)態(tài)margin
簡單來說就是:單獨(dú)設(shè)置最后一行的最后一個(gè)元素,控制其margin-right
由于每一列的數(shù)目都是固定的,因此,我們可以計(jì)算出不同個(gè)數(shù)列表應(yīng)當(dāng)多大的margin值才能保證完全左對(duì)齊。
例如,假設(shè)每行4個(gè)元素,結(jié)果最后一行只有3個(gè)元素,則最后一個(gè)元素的margin-right大小是“列表寬度+間隙大小”的話,那最后3個(gè)元素也是可以完美左對(duì)齊的。
然后,借助樹結(jié)構(gòu)偽類數(shù)量匹配技術(shù),我們可以知道最后一行有幾個(gè)元素。
例如:
- .list:last-child:nth-child(4n - 1)說明最后一行,要么3個(gè)元素,要么7個(gè)元素……
- .list:last-child:nth-child(4n - 2)說明最后一行,要么2個(gè)元素,要么6個(gè)元素……
.container { display: flex; /* 兩端對(duì)齊 */ justify-content: space-between; flex-wrap: wrap; } .list { width: 24%; height: 100px; background-color: skyblue; margin-top: 15px; } /* 如果最后一行是3個(gè)元素 */ .list:last-child:nth-child(4n - 1) { margin-right: calc(24% + 4% / 3); } /* 如果最后一行是2個(gè)元素 */ .list:last-child:nth-child(4n - 2) { margin-right: calc(48% + 8% / 3); }
那么,如果每一行的列數(shù)是不固定的呢?
這個(gè)問題的解法有很多種,其中筆者最“推崇”的是——用空白元素占位!
使用足夠的空白標(biāo)簽進(jìn)行填充占位:具體的占位數(shù)量是由最多列數(shù)的個(gè)數(shù)決定的,例如這個(gè)布局最多7列,那我們可以使用7個(gè)空白標(biāo)簽進(jìn)行填充占位,最多10列,那我們需要使用10個(gè)空白標(biāo)簽。
<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>
這種方法的缺點(diǎn)(同時(shí)也是優(yōu)點(diǎn))就是:占位的 <i>
元素寬度和margin設(shè)置必須和列表父元素一樣即可!
.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; } /* 和列表一樣的寬度和margin值 */ .container > i { width: 100px; margin-right: 10px; }
這里要左對(duì)齊,則設(shè)置i的margin-right;同樣的如果右對(duì)齊,則需設(shè)置margin-left。
還有一種目前被很多人接受的方法就是曾經(jīng)風(fēng)靡的grid布局 —— 它有天然的單側(cè)對(duì)其和方塊間隙,對(duì)熟悉grid的人來說,本文這個(gè)問題幾乎不會(huì)出現(xià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; }
答疑:
我看到文章發(fā)出后有人留言問“如果像這種模塊分布,但列數(shù)不固定且是根據(jù)可視化窗口變化決定一列放多少個(gè),但是要每個(gè)方塊的間距都是一樣的”?這種問題其實(shí)很簡單:上面這個(gè)用grid布局的代碼如果將justify-content: space-between;
換為justify-content: space-around;
就可以了。。。(雖然也會(huì)有間距變化,但是在可接受范圍,‘空白'不會(huì)顯得突兀)
現(xiàn)在的問題是因?yàn)椤皊pace-between”是按照“最兩側(cè)的貼近父容器邊緣”的方法排版的,也就是說類似“兩邊的兩個(gè)貼著邊,剩下的幾個(gè)瓜分中間的空間,每往里一層還是按這樣的方式”,也就造成了響應(yīng)式變化時(shí)由于一行內(nèi)個(gè)數(shù)變化中間會(huì)有一大片空白的效果。
最后再介紹一下這個(gè)組件:它在調(diào)用時(shí)接收兩個(gè)參數(shù)——他們是兩個(gè)event函數(shù),你需要監(jiān)聽他們,你可以得到:剛顯示組件時(shí)的當(dāng)前日期/星期幾和你點(diǎn)擊選中日期時(shí)選中的年月日和星期幾
2020-09-28更新
你可以在調(diào)用組件時(shí)傳入一個(gè)數(shù)組參數(shù) dateTimes ,它的作用:標(biāo)記哪一天的事件。它的格式如:
他將顯示如下:
結(jié)尾:
以后可能為組件增加什么功能就把布局方式更新了,到時(shí)候再回來補(bǔ)。
到此這篇關(guān)于淺析微信小程序自定義日歷組件及flex布局最后一行對(duì)齊問題的文章就介紹到這了,更多相關(guān)小程序自定義日歷組件flex布局內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript DOM元素常見操作詳解【添加、刪除、修改等】
這篇文章主要介紹了JavaScript DOM元素常見操作,包括針對(duì)dom元素的添加、刪除、修改等相關(guān)操作實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2018-05-05JS判斷輸入的字符串是否是數(shù)字的方法(正則表達(dá)式)
下面小編就為大家?guī)硪黄狫S判斷輸入的字符串是否是數(shù)字的方法(正則表達(dá)式)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11網(wǎng)站發(fā)布后Bootstrap框架引用woff字體無法正常顯示的解決方法
這篇文章主要介紹了網(wǎng)站發(fā)布到IIS后Bootstrap框架引用的woff字體無法正常顯示的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11JavaScript實(shí)現(xiàn)登錄滑塊驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)登錄滑塊驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04深入JavaScript高級(jí)程序設(shè)計(jì)之對(duì)象、數(shù)組(棧方法,隊(duì)列方法,重排序方法,迭代方法)
這篇文章主要介紹了深入JavaScript高級(jí)程序設(shè)計(jì)之對(duì)象、數(shù)組(棧方法,隊(duì)列方法,重排序方法,迭代方法)的相關(guān)資料,需要的朋友可以參考下2015-12-12封裝運(yùn)動(dòng)框架實(shí)戰(zhàn)左右與上下滑動(dòng)的焦點(diǎn)輪播圖(實(shí)例)
下面小編就為大家?guī)硪黄庋b運(yùn)動(dòng)框架實(shí)戰(zhàn)左右與上下滑動(dòng)的焦點(diǎn)輪播圖(實(shí)例)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10基于Day.js更優(yōu)雅的處理JavaScript中的日期
Day.js它能夠幫助我們處理JavaScript中的日期,本文就詳細(xì)的介紹一下Day.js的具體使用,可以更簡單的處理JavaScript中的日期和時(shí)間2021-09-09JS打開圖片另存為對(duì)話框?qū)崿F(xiàn)代碼
使用JS打開圖片另存為對(duì)話框一直都是網(wǎng)頁應(yīng)用中不可缺少的一部分,本人有些好奇,于是搜集整理了一些實(shí)現(xiàn)代碼,不知道符不符合大眾的口味,在此班門弄斧了,需要的朋友可以了解下2012-12-12