在日常開發中,大多數都是在和框架打交道,久而久之便遺忘了原生JS的感覺,個人感覺中原生JS基礎還是很重要的,所以最近就利用了空餘時間造一個輪子出來,雖然以我的水平造出來的輪子質量還是不太可靠的,但是我覺得用來練練手還是不錯的,哈哈!!
So, Let's begin!
github:github.com/Zero-jian/p…
以下是日曆的樣子,是有點難看,講究講究,重點在於JS部分,嘻嘻!!!
關於日曆元件的實現思路
- 設定預設引數
- 檢查節點引數是否傳入,否則丟擲錯誤
- 動態建立顯示本日星期幾的橫軸
- 動態建立日曆的日子
- 最後新增一點dom動作就好
先來看看建構函式內容
constructor(options) {
let defaluteOptions = {
element: null, //這是節點
startOfWeek: 1,
strings: {
week: n => {
let map = {
0: '週日',
1: '週一',
2: '週二',
3: '週三',
4: '週四',
5: '週五',
6: '週六',
}
return map[n];
},
templateDay: `<li class="currentMonth">
<span class="dayLabel">
<span class="day"></span>
<span class="unit">日</span>
</span>
</li>`
},
days: {},
}
//賦值預設引數
this.options = Object.assign({}, defaluteOptions, options);
//輪番就呼叫函式動態建立dom
this.checkOptions()._generateTime()._generateWeekDay()._generateCurrentDay();
複製程式碼
初始化建立Calendar類物件的時候設定數值,賦值預設引數以及呼叫方法來動態建立dom,相信小夥伴們看懂這段程式碼沒壓力。
該輪子我全程都是用ES6寫的,畢竟程式設計師還是要跟上潮流的!!
賦值引數後開始輪番呼叫函式,首先呼叫的是**this.checkOptions()**方法,檢查節點是否存在
checkOptions() {
//如果節點不存在直接丟擲錯誤
if (!this.options.element) {
throw new Error('element is request');
}
return this;
}
複製程式碼
接下來就是獲取當天的年月日
畢竟是日曆,獲取當前的年月日當參考還是很重要的
_generateTime() {
let data = new Date(); //時間
let year = this.options.days.year = data.getFullYear(); //年份
let month = this.options.days.month = data.getMonth() + 1; //月份
let day = this.options.days.day = data.getDate(); //日子
this.options.days.countDay = 0; //日曆總日子數為7*6=42
this.options.days.noMonth = data.getMonth() + 1; //不變的月份
this.options.days.noYear = data.getFullYear(); //不變的年份
return this;
}
複製程式碼
建立星期橫軸
_generateWeekDay() {
let {
startOfWeek,
strings
} = this.options;
let calendar = document.querySelector('.calendar');
let ol = dom.create(`<ol class="weekdays"></ol>`);
calendar.appendChild(ol);
let weekIndex = this.createArray(7, startOfWeek).map((day, i) => {
let li = dom.create(`<li>${strings.week(i)}</li>`);
//判斷是否為今天
ol.appendChild(li);
});
return this;
}
複製程式碼
dom.create是封裝好的方法,傳入模板即可建立並返回回來
this.createArray()也是封裝好的方法,本函式是建立一個長度為7的陣列,為什麼長度為7?因為週一到週日的長度為7啊,然後開始使用map對映和遍歷來建立節點並新增document.body裡面!!!
唔唔唔,去到這裡,星期橫軸就建立好了,接下來是重點部分了,就是建立對於的星期的日子日曆,其實只要掌握邏輯就好了,不過因為我是菜雞,寫的時候也有點掉坑,所以,哈哈,你們對我寫的程式碼參考參考就好了!!
接下來是重點了,就是建立日子
建立日曆日子分為三個部分,第一部分是上個月的日子,第二是本月的日子,第三部分是下個月的日子,三個部分所以把它們分別封裝起來,嫑相互影響!!
話不多說,貼上程式碼
//建立當前月份日子
_generateCurrentDay() {
let date = this.options.days;
let calendar = document.querySelector('.calendar');
let ol = dom.create(`<ol class="days"></ol>`);
let getWeek = this._getWeekWeek(date.year, date.month-1, date.day); //星期幾
let getMonth = this._getMonth(date.year, date.month) //月份天數
let getMonthDay = this._getWeekDay(); //幾號
date.countDay = 0;
date.countDay += getMonth;
calendar.appendChild(ol);
//建立當月日子模組
let dayIndex = this.createArray(42, this.options.startOfWeek).map((day, i) => {
let li = dom.create(this.options.strings.templateDay);
let span = li.querySelector('.dayLabel>.day');
//判斷日曆起止,對本月日子進行賦值
if (i >= getWeek && i <= (getMonth + getWeek)) {
span.textContent = i - getWeek;
}
//判斷是否為今天
if (i == (getMonthDay + getWeek) && date.noMonth == date.month && date.noYear == date.year) {
li.classList.add('today');
}
ol.appendChild(li);
});
document.querySelector('h1.date').appendChild(dom.create(`<p data-role="time">${date.year}-${date.month}-${date.day}</p>`));
this._generatePrevMonth()._generateNextMonth();
}
複製程式碼
建立當前月份日子的邏輯就是首先就是建立一個長度為42的陣列,因為6*7=42,陣列下標為0至42,然後獲取當月的天數以及當月一號時候是星期幾,通過計算獲取本月天數的下標範圍,然後通過迴圈進行賦值,這樣就建立了日曆本月的天數
然後是建立上個月的天數
按照慣例,貼上程式碼
_generatePrevMonth() {
let date = this.options.days;
let year = date.year;
let month = date.month;
let beginWeek = this._getWeekWeek(year,month-1,1);//本月開始星期
let countMonth = this._getMonth(year,month-1);//上月月份天數
let li = document.querySelectorAll('.dayLabel>.day');
beginWeek == 0 ? beginWeek+= 7 : ''; //如果月份開頭為星期日,會出bug,這是防止
date.countDay += beginWeek;
this.createArray(beginWeek,this.options.startOfWeek).map((day,i)=>{
if(i<beginWeek) {
//上月總天數-本月開始星期幾+1+i
li[i].textContent = countMonth - beginWeek + 1 + i;
}
});
return this;
}
複製程式碼
建立上月的日子,首先獲取本月一號是星期幾,比如是星期三就可以知道前面空的數字分別為星期日、星期一和星期二,上月的天數能佔三個位置,所以就建立一個長度為3的陣列,然後計算上月的天數,然後通過邏輯判斷進行賦值,就是如此~~~
最後就是下一個月的天數
程式碼 程式碼 程式碼
//建立下個月日子
_generateNextMonth() {
let date = this.options.days;
let year = date.year;
let month = date.month;
let beginWeek = this._getWeekWeek(year,month,1);//開始星期
let countMonth = this._getMonth(year,month+1);//下月月份天數
let li = document.querySelectorAll('.dayLabel>.day');
//data.countDay統計了上月和本月的日子數總量,直接減去即可
this.createArray(42-date.countDay , this.options.startOfWeek).map((day,i)=>{
li[date.countDay+i].textContent = i+1;
});
}
複製程式碼
這個邏輯比較簡單,就是用(6*7=42)42減去上月天數和本月天數,剩下的位置為顯示下個月的天數,所以就是這樣子!!!
把封裝好的程式碼也弄出來吧~~
//dom.create()呼叫
let dom = {
create(html) {
let template = document.createElement('template');
template.innerHTML = html;
return template.content.firstChild;
}
}
複製程式碼
//this.createArray()呼叫
//建立陣列節點
createArray(length, fill) {
let array = Array.apply(null, {
length: length
}).map(() => fill);
return array;
}
複製程式碼
動作切換部分
切換日子這裡相對來說就是比較簡單,我直接貼程式碼,你們一看就懂了
//上一個月
previousMonth() {
// this.options.days.month -= 1;
this.changeMonth('prev');
}
//下一個月
nextMonth() {
// this.options.days.month += 1;
this.changeMonth('next');
}
//回到今天
resetMonth() {
// this._generateTime();
this.changeMonth('defalut');
}
//封裝月份dom
changeMonth(status) {
let date = this.options.days;
switch(status) {
case 'prev': {
--date.month < 1 ? date.year-- ? date.month = 12 : '' : '';
break;
}
case 'next': {
++date.month > 12 ? date.year++ ? date.month = 1 : '' : '';
break;
}
case 'defalut': {
this._generateTime();
break;
}
}
//移除節點
this._generateCalendar();
//重新新增節點
this._generateCurrentDay();
}
複製程式碼
唔唔唔,整個日曆元件下來大概就是這樣子,整個流程寫下來感覺自己的思維還是有所進步的,但是其實我覺得這個輪子程式碼還是可以再封裝封裝和完善的,嘻嘻~~
輪子功能比較簡單,所以剩下的功能就等待小夥伴們自由發揮了~~
好了,第一次寫文章,熬夜寫的,突然就有靈感了,不肯睡覺,呵呵,,明天上班肯定是要打瞌睡了,呵呵~~~
本人是小白,從業將近一年,所以程式碼上有什麼錯誤,請各位大神能夠指出指出,嗯嗯,完~~