浅析微信小程序自定义日历组件及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 相关文章推荐
js判断数据类型如判断是否为数组是否为字符串等等
Jan 15 Javascript
jQuery中[attribute!=value]选择器用法实例
Dec 31 Javascript
jquery图片切换插件
Mar 16 Javascript
jQuery超酷平面式时钟效果代码分享
Mar 30 Javascript
jQuery实现的网页右下角tab样式在线客服效果代码
Oct 23 Javascript
node.js中的事件处理机制详解
Nov 26 Javascript
Vue.js实战之组件之间的数据传递
Apr 01 Javascript
jQuery实现点击DIV同时点击CheckBox,并为DIV上背景色的实例
Dec 18 jQuery
js中arguments对象的深入理解
May 14 Javascript
vue实现点击按钮下载文件功能
Oct 11 Javascript
js prototype深入理解及应用实例分析
Nov 25 Javascript
jQuery实现开关灯效果
Aug 02 jQuery
解决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错误、异常处理机制(补充)
2012/05/07 PHP
php中的注释、变量、数组、常量、函数应用介绍
2012/11/16 PHP
PHP截断标题且兼容utf8和gb2312编码
2013/09/22 PHP
php socket通信简单实现
2016/11/18 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
PhpStorm连接服务器并实现自动上传功能
2020/12/09 PHP
JQUERY 对象与DOM对象之两者相互间的转换
2009/04/27 Javascript
JQuery扩展插件Validate 5添加自定义验证方法
2011/09/05 Javascript
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
Bootstrap框架实现广告轮播效果
2016/11/28 Javascript
AngularJS 使用ng-repeat报错 [ngRepeat:dupes]
2017/01/19 Javascript
使用vuex缓存数据并优化自己的vuex-cache
2018/05/30 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
jquery实现点击弹出对话框
2020/02/08 jQuery
基于jquery实现彩色投票进度条代码解析
2020/08/26 jQuery
[01:02:53]DOTA2上海特级锦标赛主赛事日 - 5 总决赛Liquid VS Secret第二局
2016/03/06 DOTA
以一个投票程序的实例来讲解Python的Django框架使用
2016/02/18 Python
通过Py2exe将自己的python程序打包成.exe/.app的方法
2018/05/26 Python
关于python2 csv写入空白行的问题
2018/06/22 Python
python2 与 pyhton3的输入语句写法小结
2018/09/10 Python
破解安装Pycharm的方法
2018/10/19 Python
PyCharm的设置方法和第一个Python程序的建立
2019/01/16 Python
react+django清除浏览器缓存的几种方法小结
2019/07/17 Python
Python3实现配置文件差异对比脚本
2019/11/18 Python
python之语音识别speech模块
2020/09/09 Python
Python 实现进度条的六种方式
2021/01/06 Python
Django项目在pycharm新建的步骤方法
2021/03/02 Python
团员学习总结的自我评价范文
2013/10/14 职场文书
销售心得体会
2014/01/02 职场文书
五四青年节的活动方案
2014/08/20 职场文书
群众路线对照检查材料
2014/09/22 职场文书
不尊敬老师的检讨书
2014/12/21 职场文书
2015年仓库工作总结
2015/04/09 职场文书
党支部培养考察意见
2015/06/02 职场文书
nginx之queue的具体使用
2022/06/28 Servers