浅析微信小程序自定义日历组件及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使用prototype定义对象类型
Feb 07 Javascript
一个简单的jQuery插件制作 学习过程及实例
Apr 25 Javascript
根据邮箱的域名跳转到相应的登录页面的代码
Feb 27 Javascript
热点新闻滚动特效的js代码
Aug 17 Javascript
浅谈checkbox的一些操作(实战经验)
Nov 20 Javascript
一个简单的jquery的多选下拉框(自写)
May 05 Javascript
详解Backbone.js框架中的模型Model与其集合collection
May 05 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
Oct 14 Javascript
jQuery延迟执行的实现方法
Dec 21 Javascript
10个在JavaScript开发中常遇到的BUG
Dec 18 Javascript
Vue.js结合bootstrap前端实现分页和排序效果
Dec 29 Javascript
Element Popover 弹出框的使用示例
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
BBS(php &amp; mysql)完整版(七)
2006/10/09 PHP
PHP验证信用卡卡号是否正确函数
2015/05/27 PHP
phpStudy访问速度慢和启动失败的解决办法
2015/11/19 PHP
PHP封装的MSSql操作类完整实例
2016/05/26 PHP
图文详解phpstorm配置Xdebug进行调试PHP教程
2016/06/13 PHP
ThinkPHP5.0 图片上传生成缩略图实例代码说明
2018/06/20 PHP
Apply an AutoFormat to an Excel Spreadsheet
2007/06/12 Javascript
JS自动缩小超出大小的图片
2012/10/12 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
jquery 页面滚动到指定DIV实现代码
2013/09/25 Javascript
快速解决FusionCharts联动的中文乱码问题
2013/12/04 Javascript
js中split函数的使用方法说明
2013/12/26 Javascript
javascript 数组操作详解
2015/01/29 Javascript
jQuery mobile 移动web(4)
2015/12/20 Javascript
浅析vue数据绑定
2017/01/17 Javascript
flag和jq on 的绑定多个对象和方法(必看)
2017/02/27 Javascript
vue mintui-Loadmore结合实现下拉刷新和上拉加载示例
2017/10/12 Javascript
PWA介绍及快速上手搭建一个PWA应用的方法
2019/01/27 Javascript
浅析vue插槽和作用域插槽的理解
2019/04/22 Javascript
nodejs对项目下所有空文件夹创建gitkeep的方法
2019/08/02 NodeJs
es6中使用map简化复杂条件判断操作实例详解
2020/02/19 Javascript
微信小程序实现点击导航标签滚动定位到对应位置
2020/11/19 Javascript
[37:03]完美世界DOTA2联赛PWL S3 INK ICE vs GXR 第二场 12.16
2020/12/18 DOTA
python 从远程服务器下载东西的代码
2013/02/10 Python
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
使用TensorFlow实现SVM
2018/09/06 Python
python实现狄克斯特拉算法
2019/01/17 Python
Python3中的bytes和str类型详解
2019/05/02 Python
Python3.7安装keras和TensorFlow的教程图解
2020/06/18 Python
详解字符串在Python内部是如何省内存的
2020/02/03 Python
巴西电子、家电、智能手机购物网站:Girafa
2019/06/04 全球购物
英语专业职业生涯规划范文
2014/03/05 职场文书
机关道德讲堂实施方案
2014/03/15 职场文书
医院见习总结
2015/06/24 职场文书
2016高考寄语或鼓励的话语
2015/12/04 职场文书
游戏开发中如何使用CocosCreator进行音效处理
2021/04/14 Javascript