手搓微信小程序生日滑动选择😉

1,630 阅读3分钟

简单说一下功能点

微信小程序设置用户的生日,直接使用日历有些不太友好,所以选择手搓一个类似某音和某红书差不多的样式。

在实现该功能还是有一些小的注意点的,最主要的就是-->日期选择需要3级联动,因为要获取当前年份有多少月份、以及当前年份的月份有多少天。总不能今天是2023年12月3号,但滑动选项里面有明天甚至以后的日期吧。

使用的是VantWeapp组件实现的滑动效果,当然,使用其他组件的一样,结尾附源代码。

功能样式图

日期选择默认的打开样式

image.png

在选择最新日期时候

image.png

除了选择天数不会去重新拉取日期外,当滑动触发年和月的改变,都需要去拉取最新的日期。若拉取的日期的天数或月份不够上一次选择的时候,默认会选择最后一个日期等等小细节吧。

主要代码功能

自己封装的一个时间工具

/**
 * 获取有多少年份[默认截至1949]
 * @param actYear 截至到多少年份
 * @returns 年份数组
 */
export const getYear = (actYear?: number): Array<number> => {
  actYear = actYear || 1949;
  const date = new Date();
  if (actYear >= date.getFullYear()) return [1949];
  let yearArr = [];
  for (let i = actYear; i <= date.getFullYear(); i++) yearArr.push(i);
  return yearArr;
};

/**
 * 获取当前年份有多少月份
 * @param year 年份
 * @returns 月份数组
 */
export const getMonthToYear = (year: number): Array<number> => {
  const date = new Date();
  const nowYear = date.getFullYear();
  if (year > nowYear) return [1];
  let monthArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
  if (year == nowYear) {
    monthArr = [];
    for (let i = 1; i <= date.getMonth() + 1; i++) monthArr.push(i);
  }
  return monthArr;
};

/**
 * 获取当前年的月份有多少天
 * @param year 年份
 * @param month 月份
 * @returns 天数数组
 */
export const getDayToMoYe = (year: number, month: number): Array<number> => {
  const date = new Date();
  const nowYear = date.getFullYear();
  const nowMonth = date.getMonth() + 1;
  if (year > nowYear) return [1];
  let monthArr = getMonthToYear(year);
  if (month > monthArr.length) return [1];
  let dayArr = [];
  if (year == nowYear && month == nowMonth) {
    for (let i = 1; i <= date.getDate(); i++) dayArr.push(i);
    return dayArr;
  }
  for (let i = 1; i <= new Date(year, month, 0).getDate(); i++) dayArr.push(i);
  return dayArr;
};

组件代码

特别说明:手动删掉了不重要的代码,请勿直接复制

<template>
      <van-popup
        class="pd-10"
        :show="showDateChoose"
        round
        position="bottom"
        @close="showDateChoose = false">
        <view class="mt-10 flex-center-zy pd-zy-15">
          <view class="ft-color-hui" @click="showDateChoose = false">取消</view>
          <view>选择你的生日</view>
          <view class="ft-big-4 ft-color-red" @click="saveDate">保存</view>
        </view>
        <van-picker
          :columns="initDate"
          @change="onDateChange"
          :visible-item-count="3"
          :loading="dateLoding" />
      </van-popup>
</template>

<script setup lang="ts">
import { ref, onMounted, reactive } from 'vue';
import FixVue from '@/common/pages/fix_vue/FixVue';
import { getYear, getMonthToYear, getDayToMoYe } from '@/utils/TimeUtil';

//展示日期选择框和日期加载
let showDateChoose = ref(false);
let dateLoding = ref(true);

//打开日期选择
const openDate = () => {
  dateLoding.value = true;
  showDateChoose.value = true;
  //测试数据,后需要修改为动态获取的用户生日,若用户生日没有则给默认值
  initDateMethod('2001-5-10');
  dateLoding.value = false;
};

//保存日期
let newDate = ref('');
const saveDate = () => {
  if (!newDate.value) return;
  //与原本日期进行对比若不同,调用修改生日的接口。。。
};

//选择新时间
const onDateChange = (e: any) => {
  const { picker, index } = e.detail;
  if (index == 2) return (newDate.value = picker.getValues());
  const upDate = picker.getIndexes();
  const year = initDate.value[0].values[upDate[0]];
  const month = initDate.value[1].values[upDate[1]];
  const day = initDate.value[2].values[upDate[2]];
  initDate.value = [];
  const result = initDateMethod(year + '-' + month + '-' + day);
  newDate.value = picker.getValues();
  setTimeout(() => {
    picker.setColumnIndex(0, result[0]);
    picker.setColumnIndex(1, result[1]);
    picker.setColumnIndex(2, result[2]);
  }, 10);
};

//初始化年份
let initDate = ref([]);
const initDateMethod = (date: string) => {
  let dateSplit = date.split('-');
  const year = getYear();
  const month = getMonthToYear(+dateSplit[0]);
  const day = getDayToMoYe(+dateSplit[0], +dateSplit[1]);
  let yearIndex = year.indexOf(+dateSplit[0]) == -1 ? year.length - 1 : year.indexOf(+dateSplit[0]);
  initDate.value.push({
    values: year,
    defaultIndex: yearIndex
  });
  let monthIndex =
    month.indexOf(+dateSplit[1]) == -1 ? month.length - 1 : month.indexOf(+dateSplit[1]);
  initDate.value.push({
    values: month,
    defaultIndex: monthIndex
  });
  let dayIndex = day.indexOf(+dateSplit[2]) == -1 ? day.length - 1 : day.indexOf(+dateSplit[2]);
  initDate.value.push({
    values: day,
    defaultIndex: dayIndex
  });
  return [yearIndex, monthIndex, dayIndex];
};
</script>

//主要的css样式,主要添加日期后面的一些提示字,如年、月、日
<style lang="less" scoped>
::v-deep.van-picker-column__item--selected {
  color: black;
}
::v-deep[data-index='0'] {
  .van-picker-column__item--selected::after {
    content: ' 年';
  }
}
::v-deep[data-index='1'] {
  .van-picker-column__item--selected::after {
    content: ' 月';
  }
}
::v-deep[data-index='2'] {
  .van-picker-column__item--selected::after {
    content: ' 日';
  }
}
::v-deep.van-picker {
  height: 150px !important;
  margin-top: 20px;
}
</style>

结束语

至此功能就完结了,接下来已编写完成仿某信的聊天样式,如自动根据输入框弹起高度修改聊天内容触底,以及动态调整输入框的高度和最大限制等等。若有需求的小伙伴,可以聊聊,我会分享个人的想法以及做法,若需求大会写一篇文章以及源码分享。