0

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

    2023.08.06 | admin | 126次围观

    欢迎点赞!

    背景

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

    正文

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

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

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

    当前切换月份的日期显示

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

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

    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 {{(item.value==selectedDate)?'active_date':''}} {{(item.value==now_selectedDate)?'active_dates':''}}" wx:for="{{week}}">
            <view class="" bindtap="selectDate" data-date="{{item}}">
             {{item.date}}
            view>

           view>
        view>
    view>

    (代码中倒数第七、八行的判断是检验是否是当前日期(now_selectedDate)或选中日期(selectedDate),为其加特殊效果,对布局不造成影响)

    .calendar_panel{
        width100%;
        heightcalc(100% - 56rpx);
    }
    .calendar_panel_two{
        display: flex;
        flex-direction: column;
        justify-content: space-around;
    }
    .calendar_box{
        width100%;
        background#fff;
        overflow: hidden;
        display: flex;
        justify-content: space-around;
        heightcalc(100% / 6);
        align-items: center;
    }
    .weekday_label{
        font-size27rpx;
        padding12rpx 0;
        display: flex;
        align-items: center;
        overflow: hidden;
    }
    .weekday_label>view{
        box-sizing: border-box;
        padding20%;
    }
    .select_icon{
        width30rpx;
        height30rpx;
    }
    .active_date{
        backgroundrgba(0,0,0,.12);
        colorrgba(0,0,0,.6);
        overflow: hidden;
        position: relative;
    }
    .active_dates{
        backgroundrgba(0,0,0,.1);
        colorrgba(0,0,0,.5);
        position: relative;
    }
    .active_dates::before{
        content"今天";
        position: absolute;
        top0;
        left50%;
        transformtranslateX(-50%);
        color: blue;
        font-size20rpx;
    }

    布局方完成微信小程序组件传值,我满心欢喜的按下ctrl+s,发现:

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

    justify-contentspace-around;

    果不其然!

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

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

    sucess

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

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

    微信小程序自定义日历组件及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;
        margin10px;
    }
    i.lists{
       min-width:100px;
       margin10px;
    }

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

    根据个数最后一个元素动态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 {
        width24%height100px;
        background-color: skyblue;
        margin-top15px;
    }
    /* 如果最后一行是3个元素 */
    .list:last-child:nth-child(4n - 1) {
        margin-rightcalc(24% + 4% / 3);
    }
    /* 如果最后一行是2个元素 */
    .list:last-child:nth-child(4n - 2) {
        margin-rightcalc(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>

    这种方法的缺点(同时也是优点)就是:占位的 元素宽度和margin设置必须和列表父元素一样即可!

    .container {
        display: flex;
        justify-content: space-between;
        flex-wrap: wrap;
        margin-right: -10px;
    }
    .container .list {
        width100px
        height:100px;
        background-color: skyblue;
        margin15px 10px 0 0;
    }
    /* 和列表一样的宽度和margin值 */
    .container > i {
        width100px;
        margin-right10px;
    }

    这里要左对齐,则设置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-columnsrepeat(auto-fill, 100px);
        grid-gap10px;
    }
    .list {
        width100px
        height:100px;
        background-color: skyblue;
        margin-top5px;
    }

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

    结尾

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

    临近国庆学校没啥课,电脑放工作室没带回,室友电脑有点不会用,就到这吧。祝各位中秋&国庆快乐,嘿嘿!

    最后

    点个在看支持我吧

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论