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

168 阅读4分钟

经过前面的逻辑,已经可以实现基本的切换功能,接下来就是收尾的工作。

精简提炼代码

此时整个页面的代码已经非常多了,为了更好地理解和便于阅读以及使用,我将基础模式封装了一个配置初始化的函数。

通过传入组件的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配置列表,例如省市县三级级联等,都可以改写。