浅析微信小程序自定义日历组件及flex布局最后一行对齐问题


Posted in Javascript onOctober 29, 2020

最近为我开源的小项目:微信小程序扩展自定义组件库(点击去GitHub) 增加了一个新组件 —— 日历组件。
效果演示:

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

在编写过程中,因为大家都知道,日历组件是有固定行数和每一行的固定列数的(即使当前方块内没有值),所以结合小程序“数据优先”的特点,最合适的布局方式一定是flex了!

先说一下大致思路(布局上),笔者将整个组件分为两部分:分别是

  1. 头部的当前日期(年月)显示,以及左右两侧的切换按钮
  2. 当前切换月份的日期显示

头部的布局自不多说:一个 display:flex; 加上 align-items:center; 居中简直完美。
底部的日期显示我是采用的“将整体分为六行,每一行七列”的布局方式 —— 因为一个月最多31天,每一周最多7天,6X7=42,行数六行足够使用。(而且现在基本上日历都是6行7列的)

这样的话我就给每一行设置相同的class,让其再用flex规范子元素(子组件):

<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,发现:

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

可以看到:控制每一行的类是 “calendar_box”,那么毫无疑问,导致出现如图原因肯定是此类中有这样一行代码:

justify-content: space-around;

果不其然!


在本项目中,我的解决方法很简单:将这一行代码去掉,那么由此导致的宽高问题怎么解决?
这个问题,css给出了解决方案—— calc()
我将“每一行”的高度设为外部view的1/6:height:calc(100% / 6) (因为这是个组件,要用到其他地方,外部元素宽高不一定,所以要用百分比),每一行中列的宽度设为整行宽度的1/7:width:calc(100% / 7)
根据CSS文档流的特点,这些元素在一行中就会一个接一个的排列,贼好看的那种~(去这里)

答疑:
文章发出后有人留言问“为啥不全部设置calc(100% / 6)然后用flex换行?”,emmmmmmm没这个必要吧,这不是看个人喜好吗,嘿嘿。先不说这里我是采用的“周几和日期父元素同一个class,在里面只控制和‘整行'相关的属性值”的策略;其实这里也是一个语义化:一周有七个日期,那一行就放七个元素,之间互不影响 —— 你如果去GitHub看源码的话就会发现:在JS渲染日期时我就有意将每一行之间(也就是每一周)“隔离操作、单独渲染”。

当然,你也可以如代码中判断index==0(第一行)一样去判断:

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

不过就显得有点“多此一举”了。

有了calc等css3函数的“加盟”,可以预见这种纯‘原生'的解决方式将会越来越多的被使用到各种场景。

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

刚才说了,这个案例中的行列数是固定的 —— 这并不少见!那么,除了本文提出的解决方法,还能怎么做?

动态改变最后一个元素的宽度

我们都知道,flex布局中还有一个比较著名的概念就是 flex: 1;flex: auto;)了,他能动态“填满”剩余空间,那么我们再子元素同级位置再加一个元素,对他设置最小宽度为子元素相同宽度,并且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;
}

这个方法和下一个问题的第一种方法类似,但要简单很多!

警告!
经过有读者留言提醒,这种方法确实不准确(感谢@李奕威(微信用户)),当时笔者测试的时候没有考虑到所有情况而且测试用class为list的div的个数有些取巧造成了这一现象。后经过多次测试发现:这种方法受min-width的影响在一些特殊情况下可行(比如:list个数为7且一行最多四个(每行列数可小于4)时是可以的,但这种规律不是绝对的) —— 如果不是flex,它将会呈现和为最后一个元素添加“margin-right:auto”一样的效果!
所以,建议跳过这种方法,我会再探索其相关实践应用。

根据个数最后一个元素动态margin

简单来说就是:单独设置最后一行的最后一个元素,控制其margin-right
由于每一列的数目都是固定的,因此,我们可以计算出不同个数列表应当多大的margin值才能保证完全左对齐。
例如,假设每行4个元素,结果最后一行只有3个元素,则最后一个元素的margin-right大小是“列表宽度+间隙大小”的话,那最后3个元素也是可以完美左对齐的。
然后,借助树结构伪类数量匹配技术,我们可以知道最后一行有几个元素。
例如:

  • .list:last-child:nth-child(4n - 1)说明最后一行,要么3个元素,要么7个元素……
  • .list:last-child:nth-child(4n - 2)说明最后一行,要么2个元素,要么6个元素……
.container {
 display: flex;
 /* 两端对齐 */
 justify-content: space-between;
 flex-wrap: wrap;
}
.list {
 width: 24%; height: 100px;
 background-color: skyblue;
 margin-top: 15px;
}
/* 如果最后一行是3个元素 */
.list:last-child:nth-child(4n - 1) {
 margin-right: calc(24% + 4% / 3);
}
/* 如果最后一行是2个元素 */
.list:last-child:nth-child(4n - 2) {
 margin-right: calc(48% + 8% / 3);
}

那么,如果每一行的列数是不固定的呢?

这个问题的解法有很多种,其中笔者最“推崇”的是——用空白元素占位!
使用足够的空白标签进行填充占位:具体的占位数量是由最多列数的个数决定的,例如这个布局最多7列,那我们可以使用7个空白标签进行填充占位,最多10列,那我们需要使用10个空白标签。

<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> 元素宽度和margin设置必须和列表父元素一样即可!

.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;
}

这里要左对齐,则设置i的margin-right;同样的如果右对齐,则需设置margin-left。

还有一种目前被很多人接受的方法就是曾经风靡的grid布局 —— 它有天然的单侧对其和方块间隙,对熟悉grid的人来说,本文这个问题几乎不会出现:

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

答疑:
我看到文章发出后有人留言问“如果像这种模块分布,但列数不固定且是根据可视化窗口变化决定一列放多少个,但是要每个方块的间距都是一样的”?这种问题其实很简单:上面这个用grid布局的代码如果将 justify-content: space-between; 换为 justify-content: space-around; 就可以了。。。(虽然也会有间距变化,但是在可接受范围,‘空白'不会显得突兀)
现在的问题是因为“space-between”是按照“最两侧的贴近父容器边缘”的方法排版的,也就是说类似“两边的两个贴着边,剩下的几个瓜分中间的空间,每往里一层还是按这样的方式”,也就造成了响应式变化时由于一行内个数变化中间会有一大片空白的效果。


最后再介绍一下这个组件:它在调用时接收两个参数——他们是两个event函数,你需要监听他们,你可以得到:刚显示组件时的当前日期/星期几和你点击选中日期时选中的年月日和星期几

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

2020-09-28更新
你可以在调用组件时传入一个数组参数 dateTimes ,它的作用:标记哪一天的事件。它的格式如:

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

他将显示如下:

浅析微信小程序自定义日历组件及flex布局最后一行对齐问题

结尾:

以后可能为组件增加什么功能就把布局方式更新了,到时候再回来补。

到此这篇关于浅析微信小程序自定义日历组件及flex布局最后一行对齐问题的文章就介绍到这了,更多相关小程序自定义日历组件flex布局内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript英文日期(有时间)选择器
May 02 Javascript
jQuery formValidator表单验证插件开源了 含API帮助、源码、示例
Aug 14 Javascript
JQuery入门——事件切换之hover()方法应用介绍
Feb 05 Javascript
js实现点击后将文字或图片复制到剪贴板的方法
Aug 04 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
Jan 29 Javascript
限制复选框最多选择项的实现代码
May 30 Javascript
纯js实现动态时间显示
Sep 07 Javascript
详解JSON和JSONP劫持以及解决方法
Mar 08 Javascript
微信小程序的开发范式BeautyWe.js入门详解
Jul 10 Javascript
jQuery实现的记住帐号密码功能完整示例
Aug 03 jQuery
JavaScript小技巧带你提升你的代码技能
Sep 15 Javascript
详解JS数组方法
Nov 20 Javascript
解决ant Design中Select设置initialValue时的大坑
Oct 29 #Javascript
解决Ant Design Modal内嵌Form表单initialValue值不动态更新问题
Oct 29 #Javascript
微信小程序自定义yPicker组件实现省市区三级联动功能
Oct 29 #Javascript
解决ant Design Search无法输入内容的问题
Oct 29 #Javascript
js实现随机圆与矩形功能
Oct 29 #Javascript
在vue中使用jsonp进行跨域请求接口操作
Oct 29 #Javascript
基于react项目打包css引用路径错误解决方案
Oct 28 #Javascript
You might like
PHP mkdir()无写权限的问题解决方法
2014/06/19 PHP
PHP中文编码小技巧
2014/12/25 PHP
SAE实时日志接口SDK用法示例
2016/10/09 PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
2020/02/21 PHP
Javascript 继承机制实例
2009/08/12 Javascript
html页面显示年月日时分秒和星期几的两种方式
2013/08/20 Javascript
通过length属性判断jquery对象是否存在
2013/10/18 Javascript
js简单实现让文本框内容逐个字的显示出来
2013/10/22 Javascript
JS实现模仿微博发布效果实例代码
2013/12/16 Javascript
javascript遍历控件实例详细解析
2014/01/10 Javascript
jquery操作对象数组元素方法详解
2014/11/26 Javascript
使用javascript实现简单的选项卡切换
2015/01/09 Javascript
JavaScript驾驭网页-CSS与DOM
2016/03/24 Javascript
AngularJS中update两次出现$promise属性无法识别的解决方法
2017/01/05 Javascript
Angularjs实现搜索关键字高亮显示效果
2017/01/17 Javascript
NodeJS测试框架mocha入门教程
2017/03/28 NodeJs
教你完全理解ReentrantLock重入锁
2019/06/03 Javascript
使用layui实现树形结构的方法
2019/09/20 Javascript
js验证密码强度解析
2020/03/18 Javascript
微信小程序实现身份证取景框拍摄
2020/09/09 Javascript
[04:27]2014DOTA2国际邀请赛 NAVI战队官方纪录片
2014/07/21 DOTA
Python中的startswith和endswith函数使用实例
2014/08/25 Python
Django 导出 Excel 代码的实例详解
2017/08/11 Python
Python实现利用163邮箱远程关电脑脚本
2018/02/22 Python
python 多进程并行编程 ProcessPoolExecutor的实现
2019/10/11 Python
Python实现大数据收集至excel的思路详解
2020/01/03 Python
浅谈keras的深度模型训练过程及结果记录方式
2020/01/24 Python
在pycharm中实现删除bookmark
2020/02/14 Python
浅谈react路由传参的几种方式
2021/03/23 Javascript
美术教师岗位职责
2014/03/18 职场文书
年会搞笑主持词串词
2014/03/24 职场文书
大学生村官演讲稿
2014/04/25 职场文书
意向书范本
2014/07/29 职场文书
党员干部对十八届四中全会的期盼
2014/10/17 职场文书
《乘法分配律》教学反思
2016/02/24 职场文书
基于PyQt5制作一个群发邮件工具
2022/04/08 Python