Vue 組件(component)教程之實現(xiàn)精美的日歷方法示例
組件(component)是Vue最強大的功能之一。組件可以擴展HTML元素,封裝可重用的代碼,根據項目需求,抽象出一些組件,每個組件里包含了展現(xiàn)、功能和樣式。每個頁面,根據自己的需要,使用不同的組件來拼接頁面。這種開發(fā)模式使得前端頁面易于擴展,且靈活性高,而且組件之間也實現(xiàn)了解耦。
最近應公司的要求,需要開發(fā)一個精美的日歷組件(IOS , 安卓, PC 的IE9+都能運行),寫完后想把它分享出來,希望大家批評。
先來個截圖
代碼已經分享到 https://github.com/zhangKunUserGit/vue-component (本地下載)
使用方法
根據需求先說一下怎么用吧 (上面是:HTML, 下面是JS )
<date-picker v-if="showDatePicker" :date="date" :min-date="minDate" :max-date="maxDate" @confirm="confirm" @cancel="cancel" ></date-picker>
import DataPicker from './components/DatePicker.vue';
import './style.scss';
new Vue({
el: '#app',
data() {
return {
date: '2017-09-11',
minDate: '2000-09-11',
maxDate: '2020-09-11',
showDatePicker: false,
selectedDate: '點擊選擇日期',
};
},
methods: {
openDatePicker() {
this.showDatePicker = true;
},
confirm(value) {
this.showDatePicker = false;
this.selectedDate = value;
},
cancel() {
this.showDatePicker = false;
},
},
components: {
DataPicker,
},
});
我們提供了最大值、最小值和初始值,唯一不足的地方是時間格式只能是YYYY-MM-DD (2017-12-12) ,大家可以從github上拉取代碼運行看一下(由于沒有仔細測試,可能會有bug和性能問題,希望指出)。
(一)先畫好界面
這個不是重點,HTML 和 CSS,應該很簡單,大家看我的css 可能感覺我的命名太長了,只因為我們公司用,擔心其他樣式影響它(可能有其他方式吧,希望大神指出)
(二)組裝日期列表
先看代碼:
rows() {
const { year, month } = this.showDate;
const months = (new Date(year, month, 0)).getDate();
const result = [];
let row = [];
let weekValue;
// 按照星期分組
for (let i = 1; i <= months; i += 1) {
// 根據日期獲取星期,并讓開頭是1,而非0
weekValue = (new Date(year, month, i)).getDay() + 1;
// 判斷月第一天在星期幾,并填充前面的空白區(qū)域
if (i === 1 && weekValue !== 1) {
this.addRowEmptyValue(row, weekValue);
this.addRowDayValue(row, i);
} else {
this.addRowDayValue(row, i);
// 判斷月最后一天在星期幾,并填充后面的空白區(qū)域
if (i === months && weekValue !== 7) {
this.addRowEmptyValue(row, (7 - weekValue) + 1);
}
}
// 按照一周分組
if (weekValue % 7 === 0 || i === months) {
result.push(row);
row = [];
}
}
this.showDate.monthStr = monthJson[this.showDate.month];
return result;
},
我的思路是:
(1)獲取月份天數(shù),并按照星期分組;
(2)如果月份第一天不在星期一,前面填充空值。同理,如何月份最后一天不在周日,最后面填充空值,目的是:讓分的組 長度都是7,也就是一周。這樣可以用flex布局方式快速開發(fā)了;
(3)里面也包含一些限制,比如小于minDate和大于maxDate, 不讓點擊等等
(三)切換月份
(1)上一個月份
/**
* 切換到上一個月
*/
prevMonth() {
if (this.prevMonthClick) {
return;
}
this.prevMonthClick = true;
setTimeout(() => {
this.prevMonthClick = false;
}, 500);
this.fadeXType = 'fadeX_Prev';
// 如何當前月份已經小于等于minMonth 就不讓其在執(zhí)行
if (this.isMinLimitMonth()) {
return;
}
const { year, month } = this.showDate;
// 判斷當前月份,如果已經等于1(1就是一月,而不是二月)
if (month <= 1) {
this.showDate.year = year - 1;
this.showDate.month = 12;
} else {
this.showDate.month -= 1;
}
},
setTimeout()主要是讓其顯示動畫后自動消失。 fadeXType 是動畫類型
(2)下一個月份
/**
* 切換到下一個月
*/
nextMonth() {
if (this.nextMonthClick) {
return;
}
this.nextMonthClick = true;
setTimeout(() => {
this.nextMonthClick = false;
}, 500);
this.fadeXType = 'fadeX_Next';
// 如何當前月份已經大于等于maxMonth 就不讓其在執(zhí)行
if (this.isMaxLimitMonth()) {
return;
}
const { year, month } = this.showDate;
// 判斷當前月份,如果已經等于12(12就是十二月)
if (month >= 12) {
this.showDate.year = year + 1;
this.showDate.month = 1;
} else {
this.showDate.month += 1;
}
},
這里面的setTimeout() 和prevMonth方法的原理一樣。
上面兩種切換月份的功能主要注意:
a. 因為有minDate和maxDate,所以首先考慮的是不能超出這個限制。
b. 要考慮切換月份后年的變化,當月份大于12后,年加1 ,月變成 1。
(四)選擇年份
(1)點擊最上面的年,顯示年份列表
openYearList() {
if (this.showYear) {
this.showYear = false;
return;
}
const index = this.yearList.indexOf(this.selectDate.year);
this.showYear = true;
// 打開年列表,讓其定位到選中的位置上
setTimeout(() => {
this.$refs.yearList.scrollTop = (index - 3) * 40;
});
},
(2)選擇年份
selectYear(value) {
this.showYear = false;
this.showDate.year = value;
let type;
// 當日期在最小值之外,月份換成最小值月份 或者 當日期在最大值之外,月份換成最大值月份
if (this.isMinLimitMonth()) {
type = 'copyMinDate';
} else if (this.isMaxLimitMonth()) { // 當日期在最大值之外,月份換成最大值月份
type = 'copyMaxDate';
}
if (type) {
this.showDate.month = this[type].month;
this.showDate.day = this[type].day;
this.resetSelectDate(this.showDate.day);
return;
}
let dayValue = this.selectDate.day;
// 判斷日是最大值,防止另一個月沒有這個日期
if (this.selectDate.day > 28) {
const months = (new Date(this.showDate.year, this.showDate.month, 0)).getDate();
// 當前月份沒有這么多天,就把當前月份最大值賦值給day
dayValue = months < dayValue ? months : dayValue;
}
this.resetSelectDate(dayValue);
},
在切換年份時注意一下方面:
a. 考慮minDate和maxDate, 因為如果之前你選擇的月份是1月,但是限制是9月,在大于minDate(比如2017) 年份沒有問題,但是到了minDate 的具體年份(比如2010),那么月份最小值只能是九月,需要修改月份,maxDate同理。
b. 如何之前你選擇的day是31,由于切換年份后,這個月只有30天,記得把day 換成這個月最大值,也就是30。
(五)處理原始數(shù)據
其實這一條正常情況下,應該放在第一步講,但是我是根據我的開發(fā)習慣來寫步驟的。我一般都是先寫功能,數(shù)據是模擬的,等寫好了,再考慮原始數(shù)據格式和暴露具體的方法等等,因為這樣不會改來改去,影響開發(fā)和心情。
initDatePicker() {
this.showDate = { ...this.splitDate(this.date, true) };
this.copyMinDate = { ...this.splitDate(this.minDate) };
this.copyMaxDate = { ...this.splitDate(this.maxDate) };
this.selectDate = { ...this.showDate };
},
splitDate(date, addStr) {
let result = {};
const splitValue = date.split('-');
try {
if (!splitValue || splitValue.length < 3) {
throw new Error('時間格式不正確');
}
result = {
year: Number(splitValue[0]),
month: Number(splitValue[1]),
day: Number(splitValue[2]),
};
if (addStr) {
result.week = (new Date(result.year, result.month, result.day)).getDay() + 1;
result.monthStr = monthJson[result.month];
result.weekStr = weekJson[result.week];
}
} catch (error) {
console.error(error);
}
return result;
},
這里目的是:
a. 處理原始數(shù)據,把原始數(shù)據查分,用json緩存下來,這樣方便后面操作和顯示。這里面我只兼容YYYY-MM-DD的格式,其他的都不兼容,如果你想兼容其他格式,你可以修改其代碼,或者用moment.js 等其他庫幫你做這件事情。
b. 拆分后的格式如下:
year: '', month: '', day: '', week: '', weekStr: '', monthStr: '',
總結
上面就是開發(fā)這個組件的詳細講解,如有不妥,請指出批評。 仔細想想,其實這個不難,就是有點瑣碎。仔細就好
這里的所有動畫都是用的Vue 的 transition,大家可以看看官網,非常詳細。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
elementplus?中?DatePicker?日期選擇器樣式修改無效的問題及解決方案
這篇文章主要介紹了elementplus中DatePicker日期選擇器樣式修改無效的問題,DatePicker日期選擇器彈出面板默認掛載在body上,所以在組件中添加了?scoped?屬性的?style?標簽下是修改不到其樣式的,講解了datepicker的使用方法,及常見的配置項和對應的值,需要的朋友可以參考下2024-01-01
Vue $emit()不能觸發(fā)父組件方法的原因及解決
這篇文章主要介紹了Vue $emit()不能觸發(fā)父組件方法的原因及解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Fragment 占位組件不生成標簽與路由組件lazyLoad案例
這篇文章主要為大家介紹了Fragment 占位組件不生成標簽與路由組件lazyLoad案例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10

