常用前端组件date-picker(二)

183 阅读4分钟

初始化Swiper

初始化swiper主要有以下两点。

  1. 确定每个swiper的范围
  2. 确定打开后swiper的初始index

确定swiper slide

第一点比如说确定年份的最小年最大年范围,月份的最小月最大月,这里用三个对应的slide来分别表示。

//  年、月、日 slide列表
const [yearSlide, setYearSlide] = useState(null);
const [monthSlide, setMonthSlide] = useState(null);
const [daySlide, setDaySlide] = useState(null);

确定swiper index

第二点是根据传入的props确定起始日期,在确定打开后swiper的初始index所显示的值和起始日期对应。例如年份范围为1990到2025年,起始日期为2022年,那么打开后就要将初始值默认设置为2022所对应的index。这里用三个对应的index来表示。

// 初始的年、月、日index
const [yearIndex, setYearIndex] = useState(0);
const [monthIndex, setMonthIndex] = useState(0);
const [dayIndex, setDayIndex] = useState(0);

其他准备

除此之外在开始前,我们还要初始化三个swiper示例,方便我们获取到他们身上对应的属性和方法、一个初始化显示日期的变量以及一个控制date-picker显示的变量。

// date-picker 显示
const [showPicker, setShowPicker] = useState(false);
//  被选中的值
const [selectedValue, setSelectedValue] = useState('yyyy-mm-dd');
// swiper实例
const [yearSwiper, setYearSwiper] = useState(null);
const [monthSwiper, setMonthSwiper] = useState(null);
const [daySwiper, setDaySwiper] = useState(null);

生成最小、初始、最大日期所对应的年、月、日

校验并生成初始日期年、月、日

先考虑默认模式,首先要对传入的date进行校验,如果没传就设置为今天,如果传了就要校验格式是否正确,同时对计算前后年份范围的yearLength也进行校验。

/**
 * 校验日期date和yearLength的正确性
 * @param {*} date 初始日期
 * @param {*} yearLength 年份值
 */
function verifyDate(date, yearLength) {
    if(!(typeof date === 'string' && /\d{4}-\d{2}-\d{2}/.test(date))) {
        return { 
            res: false,
            msg: "您输入的date格式有误,请重新输入'yyyy-mm-dd'格式的date"
        };
    }
    if(yearLength && typeof yearLength !== 'number') {
        return { 
            res: false,
            msg: "您输入的yearLength格式有误,请重新输入number类型的yearLength"
        };
    }
    yearLength = yearLength ? yearLength : 50;
    const { year, month, day } = splitDate(date);
    if(year > year + yearLength || year < year - yearLength) {
        return { 
            res: false,
            msg: "您输入的年份不在合理范围内,请重新输入" 
        }
    } 
    if(month > 12 || month === 0) {
        return { 
            res: false,
            msg: "您输入的月份不在合理范围内,请重新输入" 
        }
    } 
    if(day > 31 || day === 0) {
        return { 
            res: false,
            msg: "您输入的日期不在合理范围内,请重新输入" 
        }
    }
    return { res: true, verifyLength: yearLength };
}

// 根据校验结果生成初始日期,并且将初始日期的年、月、日分别解出来
const today = new Date();

// 获取默认日期
let initialDate = "";
if(date) {
    const { res, msg, verifyLength } = verifyDate(date, yearLength);
    if(res === true) {
        initialDate = date;
        yearLength = verifyLength;
    } else {
        errorHandler(msg);
        return false;
    }
} else {
    // 默认日期等于今天
    initialDate = moment(today).format('YYYY-MM-DD');
    yearLength = yearLength ? yearLength : 10;
}
const { year: initYear, month: initMonth, day: initDay } = splitDate(initialDate); 

根据初始日期生成最大,最小日期年、月、日

生成最大最小日期后要对初始值是否在二者之间进行校验,因为初始值是用户输入的满足要求的合理日期值,可能超出范围进而导致后面生成slide报错。

// 获取最大日期
let maxDate = moment(today).add(yearLength, 'year').format('YYYY-MM-DD');
const { year: maxYear, month: maxMonth, day: maxDay } = splitDate(maxDate);
console.log('--最大日期maxDate--', maxYear, maxMonth, maxDay);

// 获取最小日期
let minDate = moment(today).subtract(yearLength, 'year').format('YYYY-MM-DD');
const { year: minYear, month: minMonth, day: minDay } = splitDate(minDate);
console.log('--最小日期minDate--', minYear, minMonth, minDay);

// 校验默认日期是否在最小日期和最大日期之内(这里校验过以下就无需校验,省掉大量代码)
const checkRes = moment(initialDate).isBetween(minDate, maxDate, null, "[]"); 
if(!checkRes) {
    errorHandler('您配置的initialDate超出了合理范围,请重新配置。')
    return false;
}

生成年份slide => yearSlide

这里为了对slide进行统一处理,定义了一个公共方法

/**
* 生成swiper的slide
* @param {string} type // slide类型 年 | 月 | 日 | 时 | 分
* @param {number} endDay  // 截止日期
* @param {number} startDay // 开始日期
*/
function generateSlide(type, endDay, startDay = 0) {
   let arr = [];
   const todayYear = new Date().getFullYear();
   switch(type) {
       case("year"):
           endDay = endDay ? endDay : todayYear + 50;
           // 如果startDay不是0,则endDay加1,保证循环的数据的正确
           if(startDay) endDay++;
           break;
       case("month"):
           endDay = endDay ? endDay : 12;
           // 如果startDay不是0,则endDay加1,保证循环的数据的正确
           if(startDay) endDay++;
           break;
       case("day"):
           endDay = endDay ? endDay : 31;
           // 如果startDay不是0,则endDay加1,保证循环的数据的正确
           if(startDay) endDay++;
           break;
       case("hour"):
           endDay = endDay ? endDay : 24;
           break;
       case("minute"):
           endDay = endDay ? endDay : 12;
           break;
   }
    for(var i = startDay; i < endDay; i++){
        arr.push({
            value: startDay === 0 ? i + 1 : i, // 如果是从0开始需要+1,如果不是则不需要
            key: type + i,
        });
    }
   return arr;
}

/**
 * 当start不传时,默认为0,循环时每一项为 i + 1,例如第0项的值为1
 * 当start传了时明显不能这么循环,因此将循环的每一项变为i,最大值加1,来保证循环数据正确
 * 例如从12循环到31,  12 <= i < 32
 */

使用该方法生成年份的slide,将最小年,最大年传入即可。

const yearSlideInit = generateSlide('year', maxYear, minYear);

生成年份对应的index => yearIndex

年份的index很好生成,举个🌰。

[1996, 2012] 1996年的index为0; 2000年的index为4。

因此,index为初始年份减去最小年份。

const yearIndexInit = initYear - minYear;