浅析微信小程序自定义日历组件及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 相关文章推荐
In Javascript Class, how to call the prototype method.(three method)
Jan 09 Javascript
msn上的tab功能Firefox对childNodes处理的一个BUG
Jan 21 Javascript
JS 的应用开发初探(mootools)
Dec 19 Javascript
jquery判断checkbox(复选框)是否被选中的代码
Oct 20 Javascript
判断对象是否Window的实现代码
Jan 10 Javascript
JavaScript动态插入script的基本思路及实现函数
Nov 11 Javascript
js操纵dom生成下拉列表框的方法
Feb 24 Javascript
jQuery搜索同辈元素方法
Feb 10 Javascript
基于jquery实现智能表单验证操作
May 09 Javascript
AngularJs学习第五篇从Controller控制器谈谈$scope作用域
Jun 08 Javascript
jQuery层次选择器用法示例
Sep 09 Javascript
JS 封装父页面子页面交互接口的实例代码
Jun 25 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优化那些事(经验分享)
2014/11/27 PHP
php实现跨域提交form表单的方法【2种方法】
2016/10/17 PHP
Yii2中简单的场景使用介绍
2017/06/02 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
QQ登录简单实现代码
2021/03/09 Javascript
js常见表单应用技巧
2008/01/09 Javascript
javascript 自定义事件初探
2009/08/21 Javascript
jquery UI 1.72 之datepicker
2009/12/29 Javascript
文本框获得焦点和失去焦点的判断代码
2012/03/18 Javascript
利用JQuery和JS实现奇偶行背景颜色自定义效果
2012/11/19 Javascript
JavaScript对象和字串之间的转换实例探讨
2013/04/21 Javascript
兼容主流浏览器的iframe自适应高度js脚本
2014/01/10 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
2016/12/02 Javascript
canvas实现动态小球重叠效果
2017/02/06 Javascript
React中使用collections时key的重要性详解
2017/08/07 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
2017/08/14 Javascript
react实现菜单权限控制的方法
2017/12/11 Javascript
浅谈VUE监听窗口变化事件的问题
2018/02/24 Javascript
解决layUI的页面显示不全的问题
2019/09/20 Javascript
Vue组件通信中非父子组件传值知识点总结
2019/12/05 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
2020/07/24 Javascript
在vue中使用回调函数,this调用无效的解决
2020/08/11 Javascript
[04:23]DOTA2上海特锦赛小组赛第一日 TOP10精彩集锦
2016/02/27 DOTA
Python入门篇之编程习惯与特点
2014/10/17 Python
python执行外部程序的常用方法小结
2015/03/21 Python
在linux下实现 python 监控usb设备信号
2019/07/03 Python
python实现大战外星人小游戏实例代码
2019/12/26 Python
Meli Melo官网:名媛们钟爱的英国奢侈手包品牌
2017/04/17 全球购物
美国婴童服装市场上的领先品牌:Carter’s
2018/02/08 全球购物
桥梁工程专业求职信
2014/04/21 职场文书
2014年三万活动总结
2014/04/26 职场文书
2015年父亲节活动总结
2015/02/12 职场文书
2015年秋季学校开学标语
2015/07/16 职场文书
2015秋季开学典礼致辞
2015/07/16 职场文书
思想工作总结范文
2015/08/12 职场文书
经典哲理警句:志不真则心不热,心不热则功不贤
2019/11/14 职场文书