经过前面的逻辑,已经可以实现基本的切换功能,接下来就是收尾的工作。
精简提炼代码
此时整个页面的代码已经非常多了,为了更好地理解和便于阅读以及使用,我将基础模式封装了一个配置初始化的函数。
通过传入组件的props对不同环境进行区分,并传入对应的配置,然后返回对应配置下的三种swiper的slide、index及对应的yearSlideChange和monthSlideChange。在使用统一的useState方法进行统一赋值。
同时将很多的通用工具类方法,统一放到一个工具类文件中,不占用主入口资源。
// index.js
import defaultHandler from "./default";
import beforeHandler from "./before";
import afterHandler from "./after";
import durationHandler from "./duration";
useEffect(() => {
configInit(props);
}, [])
// 这里使用一个useRef来保存当前的模式,方便后面使用
const currentModule = useRef();
/**
* 根据传入的props生成不同的swiper配置
* @param {*} props 传入进来的属性
*/
function configInit(props) {
const { date, yearLength, before, after, duration } = props;
const situation = distinguishSituation(props);
switch(situation) {
case "default":
console.log('%c当前是default模式', `${consoleStyle}`);
currentModule.current = 'default';
const defaultConfig = defaultHandler(date, yearLength);
swiperInit(defaultConfig);
break;
case "before":
console.log('%c当前是before模式', `${consoleStyle}`);
currentModule.current = 'before';
const beforeConfig = beforeHandler(before);
swiperInit(beforeConfig);
break;
case "after":
console.log('当前是after模式', `${consoleStyle}`);
currentModule.current = 'after';
const afterConfig = afterHandler(after);
swiperInit(afterConfig);
break;
case "duration":
console.log('当前是duration模式', `${consoleStyle}`);
currentModule.current = 'duration';
const durationConfig = durationHandler(duration);
swiperInit(durationConfig);
break;
default:
return false;
}
}
// defaut.js | before.js | ...
/**
* before处理程序
* @param {Object} before
*/
export default function beforeHandler(before) {
// 初始化年份slide及其index
const yearSlideInit = generateSlide('year', maxYear, minYear);
const yearIndexInit = initYear - minYear;
// 初始化月份slide及其index ,初始化天数及其index
let monthSlideInit = [];
let daySlideInit = [];
let monthIndexInit = 0;
let dayIndexInit = 0;
// ...
// yearSlideChange事件
function yearChangeFun(currentYear, currentMonth, currentDay) {
// ...
}
// monthSlideChange事件
function monthChangeFun(currentYear, currentMonth, currentDay) {
// ...
}
return {
dateInit: initialDate,
yearSlideInit,
yearIndexInit,
monthSlideInit,
monthIndexInit,
daySlideInit,
dayIndexInit,
yearChangeFun,
monthChangeFun,
}
}
swiperInit对配置统一赋值
这里的两个方法yearSlideChange和monthSlideChange使用useRef()设置了初始值,为了方便后续的调用。
/**
* 借助useRef可以跨越生命周期的特性来定义变量
* 使用普通变量定义; 无法在跨越生命周期useEffect后拿到值。
* 使用useState: swiper无法识别useState定义的初始化函数
*/
const yearChange = useRef();
const monthChange = useRef();
/**
* 初始化swiper
* @param {object} config
*/
function swiperInit(config) {
const {
dateInit,
yearSlideInit, yearIndexInit, monthSlideInit,
monthIndexInit, daySlideInit, dayIndexInit,
yearChangeFun, monthChangeFun
} = config;
// 初始化默认显示的日期
setSelectedValue(dateInit);
// 初始化slide
setYearSlide(yearSlideInit);
setMonthSlide(monthSlideInit);
setDaySlide(daySlideInit);
// 初始化index
setYearIndex(yearIndexInit);
setMonthIndex(monthIndexInit);
setDayIndex(dayIndexInit);
// 初始化slideChange
yearChange.current = yearChangeFun;
monthChange.current = monthChangeFun;
}
封装yearSlideChange及monthSlideChange
从对应模式中取出来后赋值给对应的useRef后,在index.js中的yearSlideChange中进行统一调用和更新。
/**
* 年份slide改变事件
* @param {Swiper} swiper 年份swiper
*/
function yearSlideChange(swiper) {
if(yearIndex !== 0 && !yearFlag) return;
const currentYear = yearSlide[swiper.activeIndex].value;
const currentMonth = monthSlide[monthSwiper.activeIndex].value;
const currentDay = daySlide[daySwiper.activeIndex].value;
console.log('----yearSlideChange切换后的日期----', currentYear, currentMonth, currentDay);
const config = yearChange.current(currentYear, currentMonth, currentDay);
const { monthSlideList, monthActiveIndex, daySlideList, dayActiveIndex } = config;
setMonthSlide(monthSlideList);
setDaySlide(daySlideList);
monthSwiper.activeIndex = monthActiveIndex;
daySwiper.activeIndex = dayActiveIndex;
}
/**
* 月份slide改变事件
* @param {Swiper} swiper 月份swiper
*/
function monthSlideChange(swiper) {
if(monthIndex !== 0 && !monthFlag) return;
const currentYear = yearSlide[yearSwiper.activeIndex].value;
const currentMonth = monthSlide[swiper.activeIndex].value;
const currentDay = daySlide[daySwiper.activeIndex].value;
const config = monthChange.current(currentYear, currentMonth, currentDay);
const { daySlideList, dayActiveIndex } = config;
setDaySlide(daySlideList);
daySwiper.activeIndex = dayActiveIndex;
}
关闭date-picker
关闭时除了对showPicker赋值false外,还要对一些变量进行统一修改,因此设置了一个统一的方法调用。
/**
* 关闭picker事件
*/
function closePicker() {
console.log('--销毁日期控件--');
setShowPicker(false);
setYearFlag(false);
setMonthFlag(false);
revertPageScroll(); // 恢复页面滚动
}
点击确定按钮赋值
再点按钮时分别取到三个swiper的当前值,获取到当前日期。然后根据不同模式的格式要求对selectValue进行更新赋值,随后在重新调用configInit更新swiper配置。
/**
* 确定按钮点击事件
*/
function confirmHandler() {
const yearSelect = yearSlide[yearSwiper.activeIndex].value;
const monthSelect = monthSlide[monthSwiper.activeIndex].value;
const daySelect = daySlide[daySwiper.activeIndex].value;
// 根据现有时间重新初始化
const tempProps = cloneDeep(props);
if(currentModule.current === 'default') {
// 默认模式直接给date赋值 当前选中的时机
tempProps.date = `${yearSelect}-${monthSelect}-${daySelect}`;
} else {
// 其他模式给对应对象里的初始日期赋值
tempProps[currentModule.current].initialDate = `${yearSelect}-${addZero(monthSelect)}-${addZero(daySelect)}`;
}
// 根据新日期做初始化
configInit(tempProps);
closePicker();
}
点击取消按钮恢复原状
与确定按钮事件相似,不同的是采用未确定的selectValue重新进行初始化,恢复各个Swiper的配置。
/**
* 取消按钮点击事件
*/
function cancelHandler() {
// 根据现有时间重新初始化
const tempProps = cloneDeep(props);
if(currentModule.current === 'default') {
// 默认模式直接给date赋值 当前选中的时机
tempProps.date = selectedValue;
} else {
// 其他模式给对应对象里的初始日期赋值
tempProps[currentModule.current].initialDate = selectedValue;
}
// 根据新日期做初始化
configInit(tempProps);
closePicker();
}
打开picker
/**
* 打开date-picker
*/
function openPicker() {
setShowPicker(true);
disablePageScroll(); // 禁止页面滚动
setTimeout(() => {
setYearFlag(true);
setMonthFlag(true);
}, 0)
}
自定义配置
以上就实现了基本想要的功能,想要什么其他的功能可以直接通过引入对应的配置文件来初始化swiper。
也可以根据需求增改自己的配置,例如增加打开、关闭、slideChange、取消、确定的回调事件,也可以在回调事件里返回出来自己想要的变量。
也可以采用Jquery的方式动态生成swiper,为其传入一个已经生成好的swiper配置列表,例如省市县三级级联等,都可以改写。