手動開發一個日曆元件

WangQingye發表於2019-03-04

前言

應用場景是公司的一個每日推薦專題需要加入日曆功能,點選日曆可以跳轉到當日的推薦。

設計圖:

手動開發一個日曆元件

關於日曆的實現

日曆實現的核心是利用js的Date物件(專案程式碼環境是依賴在vue當中)。

第一步:首頁展示

我們首先考慮我們日曆的第一頁,當前月。

要展示我們的當前月,首先我們需要三個資料:

  • 當前年份
  • 當前月份
  • 月份下的日期列表

這些資料的初始化(注意這裡只是初始化,因為在日曆的使用過程中,他們是會隨著互動而變化的)狀態很好獲得,前兩個資料我們只需要通過:

this.curdate = new Date();
this.calendarMonth = this.curDate.getMonth() + 1; // 注意月份加1
this.calendarYear = this.curDate.getFullYear();
複製程式碼

值得一提的是我們的日期資料,因為這裡涉及到2個變數,第一個是每個月份的天數是不一樣的。第二個是每個月的1號是星期幾也是不固定的(而這個星期幾,則會影響到顯示上,1號應該從哪裡開始)。

直接貼上最終的獲取列表的程式碼:

/* 返回當月的日期表 */
getMonthList() {
  // new Date()中的最後一個引數為0,表示的是當月的最後一天,
  // 因此我們通過這一句獲得的就是傳入的年月的當月最後一天。
  let date = new Date(this.calendarYear, this.calendarMonth, 0);
  // 獲得當月的最後一天的日期號,就知道了當月有多少天
  this.days = date.getDate();
  // setDate(1)的作用是把日期變為當月的第一天
  date.setDate(1);
  // 在通過getDay(),就能知道當月的第一天是星期幾
  let day = date.getDay();
  // 獲得1號是星期幾後,在日曆上做一個偏移,這裡我採用的是補0
  let delay = day - 1;
  // 因為星期天在getDay的返回中是0,固特殊處理
  if (day == 0) {
  	delay = 6;
  }
  let list = [];
  for (let i = 0; i < this.days + delay; i++) {
    if (i < delay) {
      list.push(0);
    } else {
      list.push(i - delay + 1)
    }
  }
  return list;
},
// 通過這個函式我們就獲得了當月的列表,格式類似於[0,0,0,1,2,3...31]
複製程式碼

第二步:響應變化

變化主要分為兩個方面:點選左右箭頭改變月份,點選具體的日期。

改變月份:

改變月份時我們要做的主要工作是改變我們用於記錄時間的變數(使用mvvm框架的好處是我們不需要關注檢視層面的改變,只需要專注我們的變數):

changeMonth(flag) {
  // flag 記錄左右滑動,對應到月份就是加1和減1
  this.curDate.setMonth(this.calendarMonth - 1 + flag);
  // setNowDate() 函式裡面包括了我們每次改變日期時所需要做的工作,比如重新整理月份列表(即重新呼叫getMonthList函式等其他一些功能)
  //如果我們要把日曆做成一個元件,那麼我們的函式中肯定需要觸發一個事件鉤子以反饋給外部例如:$emit('monthChange')
  this.setNowDate();
},
複製程式碼
改變日期:
changeDay(day, el) {
  // 改變我的當前顯示日期
  this.curDate.setDate(day);
  // clickedMonth是用來記錄我當前點選的月份,這個變數只隨點選改變,而不隨頁面翻動改變,主要是用來判斷當前日期的樣式用的。
  this.clickedMonth = this.calendarMonth;
  this.clickedYear = this.calendarYear;
  // 獲取當前日曆的推薦資料(具體邏輯不贅述,這裡可以進行自己需要的操作)
  this.getData(new Date(this.calendarYear, this.calendarMonth - 1, day), true)
  this.setNowDate();
},
複製程式碼

點選了日期後,我們的樣式也會隨之改變:

// 計算樣式的函式
calDayCls(day) {
  let cls = "calendar-li";
  /* 檢視當前 */
  if (day == this.calendarDay && this.calendarYear == this.clickedYear && this.calendarMonth == this.clickedMonth) {
    cls += ' calendar-li-active';
  }
  return cls
}
複製程式碼

至此,我們的日曆的核心功能就完成了,核心函式如下:

setNowDate // 改變控制當前日曆顯示的變數
changeMonth // 改變月份
getMonthList // 獲取月份日期表
changeDay // 改變日期
calDayCls // 計算當前日期的樣式
複製程式碼

有了這些核心部分,就基本實現了日曆的核心功能,然後就可以在上面新增更多的自定義的功能了,因為很多是涉及到我自己專案中個性化的東西,不具備過多參考價值,固沒有在程式碼體現。

相關文章