浅析微信小程序自定义日历组件及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弹窗代码 可以指定弹出间隔
Jul 03 Javascript
JavaScript 判断浏览器是否支持SVG的代码
Mar 21 Javascript
MyEclipse取消验证Js的两种方法
Nov 14 Javascript
JQuery表单验证插件EasyValidator用法分析
Nov 15 Javascript
基于jQuery实现多层次的手风琴效果附源码
Sep 21 Javascript
解决jQuery使用JSONP时产生的错误
Dec 02 Javascript
js替换字符串中所有指定的字符(实现代码)
Aug 17 Javascript
jquery过滤特殊字符',防sql注入的实现方法
Aug 17 Javascript
[原创]javascript typeof id==='string'?document.getElementById(id):id解释
Nov 02 Javascript
vue中锚点的三种方法
Jul 06 Javascript
JS Object.preventExtensions(),Object.seal()与Object.freeze()用法实例分析
Aug 25 Javascript
Element Input输入框的使用方法
Jul 26 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
PHP5+UTF8多文件上传类
2008/10/17 PHP
php强大的时间转换函数strtotime
2016/02/18 PHP
PHP图片加水印实现方法
2016/05/06 PHP
laravel框架模型中非静态方法也能静态调用的原理分析
2019/11/23 PHP
jQuery简单实现验证邮箱格式
2015/07/15 Javascript
javascript 中的 delete及delete运算符
2015/11/15 Javascript
jQuery中trigger()与bind()用法分析
2015/12/18 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
Angular使用 ng-img-max 调整浏览器中的图片的示例代码
2017/08/17 Javascript
Angular实现图片裁剪工具ngImgCrop实践
2017/08/17 Javascript
Vue-router路由判断页面未登录跳转到登录页面的实例
2017/10/26 Javascript
nodejs连接mysql数据库及基本知识点详解
2018/03/20 NodeJs
说说Vuex的getters属性的具体用法
2019/04/15 Javascript
javascript实现5秒倒计时并跳转功能
2019/06/20 Javascript
javascript如何实现create方法
2019/11/04 Javascript
详解微信小程序工程化探索之webpack实战
2020/04/20 Javascript
[01:11]回顾历届DOTA2国际邀请赛中国区预选赛
2017/06/26 DOTA
[01:23]2019完美世界全国高校联赛(春季赛)合肥全国总决赛
2019/06/10 DOTA
[06:48]DOTA2-DPC中国联赛2月26日Recap集锦
2021/03/11 DOTA
详解numpy的argmax的具体使用
2019/05/27 Python
python os.path.isfile 的使用误区详解
2019/11/29 Python
使用python无账号无限制获取企查查信息的实例代码
2020/04/17 Python
Python 实现敏感目录扫描的示例代码
2020/05/21 Python
无惧面试,带你搞懂python 装饰器
2020/08/17 Python
Python pymysql模块安装并操作过程解析
2020/10/13 Python
用Python自动清理电脑内重复文件,只要10行代码(自动脚本)
2021/01/09 Python
简洁的英文求职信范文
2014/05/03 职场文书
优秀研究生主要事迹
2014/06/03 职场文书
道路交通事故人身损害赔偿协议书
2014/11/19 职场文书
2015试用期转正工作总结
2014/12/12 职场文书
党风廉政建设心得体会(2016最新版)
2016/01/22 职场文书
python基于机器学习预测股票交易信号
2021/05/25 Python
django 认证类配置实现
2021/11/11 Python
JavaScript中MutationObServer监听DOM元素详情
2021/11/27 Javascript
微信小程序APP的事件绑定以及传递参数时的冒泡和捕获
2022/04/19 Javascript
MySQL深分页问题解决思路
2022/12/24 MySQL