手寫日曆組件

效果預覽




























各類各樣的產品層出不窮,公司層面嚴抓產品風格,尋求在設計上脫穎而出,這就加大了對前端的開發難度,定製化的場景愈來愈多通用型的組件庫已經不可以知足咱們的需求了,摸魚的時候立馬對這方面的能力進行增強~~javascript

實現思路

  • 算出這個月的第一天是從星期幾開始,也就是日曆列表的前置空白部分。
  • 封裝一個函數根據年份,月份計算出這個月到底有多少天,與前置空白部分進行拼接渲染。
  • 日曆有兩種模式,單選以及選擇起始-結束,根據傳入的參數不一樣選擇不一樣的模式,進行處理。
  • 選中號數時,大於當前號數的沒法選擇,年份,月份都是如此。例如:今天是23號,大於23號的所有沒法選中。

事件處理

入口函數:前端

$(function(){
    
    function init() {
        ChangeData();   // 計算本月有多少天
        render();       // 渲染頁面
        bindEvent();    // 初始化事件綁定
    }
    
    init();

})(document)
複製代碼

當即執行函數+init是不少插件的寫法 例如:new swiper().init()java

function ChangeData() {
        // 獲取一個月有多少天
        days = getMonthDay( year, month );
        // 建立當前這個月的日期天數
        daysArr = generateArray( 1, days );
        // 前置空白部分的個數
        weekday = getweekday( year, month );
        // 前置空白部分的集合
        weekdayArr = generateArray( 1, weekday );
        // 當前日期
        showTitle = `${year}${month}月`
    }
複製代碼

切換月份的事件:git

function changeMonthHandler( isAdd, callback ) {
    // isAdd 爲 1 是前進 爲 0 是後退
    if ( isAdd === '1' ) {
        month += 1;
        let Year = month > 12 ? year + 1 : year;
        if ( !checkRange( Year ) ) {
            month = month > 12 ? 1 : month;
            year = Year;
            _obj.month = month;
            _obj.year = Year;
            ChangeData();
            callback(_obj);
        }

    } else {
        month -= 1;
        let Year = month < 1 ? year - 1 : year;
        if ( !checkRange( Year ) ) {
            month = month < 1 ? 12 : month;
            year = Year;
            _obj.month = month;
            _obj.year = Year;
            ChangeData();
            callback(_obj);
        }
    }
}
// 判斷傳入的年份是否越界
function checkRange( year ) {
    let overstep = false;
    if ( year < minYear || year > maxYear ) {
        overstep = true;
    }
    return overstep;
}

複製代碼

子級觸發父級事件並傳遞前進後退的標識和回調,前進則月份+1,而且判斷當前月份是否超過12月超過則把年份+1,並觸發 ChangeData 事件從新計算此月有多少天, 後退的事件同理。markdown

單選的點擊事件:app

function openDisAbled( day, callback ) {
        let bool = true;
        if ( day == '' ) return bool;
        
        let date = `${year}/${month}/${day}`;
        // 最小的日期限制
        let minTime = `${min.year}/${min.month}/${min.day}`;
        // 最大的日期限制
        let maxTime = `${max.year}/${max.month}/${max.day}`;
        // 當前日期轉換時間戳
        let timestamp = new Date(date).getTime();
        // 若是點擊的日期再此月內就執行
        if ( timestamp >= new Date(minTime).getTime() && timestamp <= new Date(maxTime).getTime() ) {
            bool = false;
        }
        callback( bool, _obj );
    }
複製代碼

子級進行點擊觸發父級事件傳入號數以及回調,前置空白部分是空的,因此若是等於空直接退出沒法點擊。上述代碼的判斷是決定是否可選擇的日期,例以下個月的日期我是沒法選中的。若是當前如期大於最小日期而且當前日期小於最大日期則bool置爲false,回調回子級,可進行點擊。minTime的默認值是1950,maxTime的最大值是2050函數

子級接收進行處理:oop

selectTime( el ) {
    let day = $(el).attr('index');
    ScreenAbled( 'section', { day }, ( res, { mode }) => {
        // 若是 bool 傳回來是 true 直接退出
        if ( res ) return;
        // date 單選模式
        if ( mode === 'date' ) {
            $(el)
                .addClass('active')      // 選中的添加高亮樣式
                .siblings('.active')     // 篩選出同級帶有 active 的元素
                .removeClass('active');  // 刪除 active 類
                // 觸發父級事件 寫入選中日期
                ScreenAbled('alone', { day: day });    
        }
    })
}
複製代碼

起始-結束事件:ui

  • 父級
function ChangeDouble( callback, day ) {
        let date = `${year}-${month}-${day}`;
        // startDate存放起始時間
        let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date( startDate.replace(/\-/g,'/') ).getTime()
        if ( isStart || compare ) {
            startDate = date;
            isStart = false;
            callback( 'start' );
            startTime = `${year}-${month}-${day}`;
        } else {
            isStart = true;
            callback( 'end' );
            endTime = `${year}-${month}-${day}`;
        }
    }
複製代碼

compare的做用是篩選出結束時間大於起始時間的狀況,例如:起始5/23 結束5/13,這種狀況不成立則須要操做者從新選擇時間,url

  • 子級
// 觸發父級事件
ScreenAbled( 'ChangeDouble', { day }, type => {
    // 起始時間處理
    if ( type === 'start' ) {
        // 獲取出全部小字的元素進行重置
        $('.seat').find('.slot').text(' ');
        // 爲當前點擊的元素添加小字提示
        $(el).find('.slot').text('起始');
        
        $(el)
            .addClass('active')    // 爲當前選中元素添加高亮
            .siblings('.active')   // 篩選出帶 active 的元素
            .removeClass('active') // 刪除 active 類

        $(el)            
            .siblings('.section')   // 篩選出帶 section 的元素
            .removeClass('section') // 刪除 section 類
            
        // 存儲開始的下標
        CollectIndex = day;
        return false;
    }
    // 結束時間處理
    $(el)
        .addClass('active')      // 添加高亮樣式
        .siblings('.sign')       // 篩選出帶有 sign 的元素
        .slice( CollectIndex, day - 1 )   // 篩選出 起始 - 結束日期區間的元素
        .addClass('section')              // 爲此區間的元素添加高亮樣式

    $(el).find('.slot').text('結束');
});
複製代碼

選中起始以及結束時須要在盒子內用小字提示操做者,子級的處理就是動態添加刪除樣式。

最後:

之後碰到定製化需求閉上眼睛思考片刻,立馬給提需求的人來個過肩摔再加上一套軍體拳,讓他上不了班這個需求就不用搞了,哈哈。 以上只說明瞭比較重要的幾個函數完整的 源碼在這 感謝你們的閱讀,但願看完你們能有所收穫! 以爲有用就點個贊吧,你的點贊是我創做的最大動力~

相關文章
相關標籤/搜索