一个很很很简单的移动端日历
不知道得多久没有写过文章了,从今年开始心情就一直很浮躁,静不下来...
这次写这个东西其实也很简单,主要是帮其他项目的同事写的,有些东西其实还可以继续封装的,但是我太懒了,就交给jym了。
先上图看看效果吧
主要依赖
amfe-flexible
postcss-pxtorem
dayjs
vant
这里主要说一下 amfe-flexible
和 postcss-pxtorem
,这个就是用来做移动端的适配,就像一般UI给的设计稿都是750px的,但是我们在实际开发的时候可能是不同的,所以用这个来做适配,下面是配置文件
postcss.config.js
const autoprefixer = require('autoprefixer');
const px2rem = require('postcss-pxtorem');
module.exports = {
plugins: [autoprefixer(), px2rem({
rootValue: 75, unitPrecision: 5, propList: ['*'], selectorBlackList: [
//这里样式需要排除vant组件的,因为vant本身就是移动端的样式了
'van-'
]
})],
};
主要逻辑
工具类
这些工具类就是普通的获取月数什么的,没有什么好讲的
calendar.js
// 判断是否周末
export const isWeekend = (date) => {
return [0, 6].includes(new Date(date).getDay())
}
// 获取年份
export const getDateYear = (date) => {
return new Date(date).getFullYear()
}
// 获取月份
export const getDateMonth = (date) => {
return new Date(date).getMonth() + 1
}
// 获取月份天数
export const getMonthDay = (date) => {
let year = new Date(date).getFullYear()
let month = new Date(date).getMonth() + 1
return new Date(year, month, 0).getDate()
}
// 获取月份第一天是周几
export const getMonthFirstDayOrder = (date) => {
let year = new Date(date).getFullYear()
let month = new Date(date).getMonth()
return new Date(year, month, 1).getDay()
}
// 获取上个月有多少天
export const getPrevMonthDay = (date) => {
let year = new Date(date).getFullYear()
let month = new Date(date).getMonth()
if (month === 0) {
year--
month = 12
}
return new Date(year, month, 0).getDate()
}
月份处理
这里我是采用二维数组的方式来处理每周的数据,而且我们处理月份的时候需要考虑下面几点
- 普通月份处理(这不是说废话吗),即每个月的第一天是星期几,排在第几位
- 上个月/下个月处理,上个月是几月份,多少天,是否在同一年(下个月同理)
- 周末(这里就不考虑节假日什么的了)
- 要显示多少周,最多可能有6周(1号在周六,因为我这里是以周日为第一位,然后有31天的情况)
下面就是主要的逻辑处理代码了
calendar.vue
// 初始化日历数据
initMonthData(date) {
this.dateArr = [[], [], [], [], [], []]
// 每个月第一天排在第几位
let firstDayOrder = getMonthFirstDayOrder(date)
// 选择器选择的年份
let selectedYear = getDateYear(date)
// 选择器选择的月份
let selectedMonth = getDateMonth(date)
// 选择器选择的月份天数
let selectedMonthDay = getMonthDay(date)
// 选择器选择的月份的上个月的总天数
let prevMonthDay = getPrevMonthDay(date)
// 月份渲染记数
let selectedCountDay = 0
// 下个月月份渲染记数
let nextMonthCountDay = 0
// 是否下个月
let isNextMonth = false
for (let weekIndex = 0; weekIndex < 6; weekIndex++) {
for (let dayIndex = 0; dayIndex < 7; dayIndex++) {
if (weekIndex === 0) {
// 第一周需要对某一个月第一天做定位
if (firstDayOrder <= dayIndex) {
// 当前月
selectedCountDay += 1
this.$set(this.dateArr[weekIndex], dayIndex, {
date: new Date(
selectedYear,
selectedMonth - 1,
selectedCountDay
),
status: {
isCurr: true, // 是否当月
isPrev: false, // 是否上个月
isNext: false, // 是否下个月
// 是否周末
isWeekend: isWeekend(
new Date(selectedYear, selectedMonth - 1, selectedCountDay)
)
}
})
} else {
// 上个月 因为选择月份是当前月 上个月需要减去1 然后new Date()还需要再减去1
let prevMonth = selectedMonth === 1 ? 11 : selectedMonth - 2
let prevMonthYear =
selectedMonth - 1 === 0 ? selectedYear - 1 : selectedYear
this.$set(this.dateArr[weekIndex], dayIndex, {
date: new Date(
prevMonthYear,
prevMonth,
prevMonthDay - firstDayOrder + dayIndex + 1
),
status: {
isCurr: false,
isPrev: true,
isNext: false,
isWeekend: isWeekend(
new Date(
prevMonthYear,
prevMonth,
prevMonthDay - firstDayOrder + dayIndex + 1
)
)
}
})
}
} else {
selectedCountDay += 1
isNextMonth = selectedCountDay > selectedMonthDay
if (!isNextMonth) {
// 当前月
this.$set(this.dateArr[weekIndex], dayIndex, {
date: new Date(
selectedYear,
selectedMonth - 1,
selectedCountDay
),
status: {
isCurr: true,
isPrev: false,
isNext: false,
isWeekend: isWeekend(
new Date(selectedYear, selectedMonth - 1, selectedCountDay)
)
}
})
} else {
// 下个月
let nextMonth = selectedMonth === 12 ? 0 : selectedMonth
let nextYear =
selectedMonth === 12 ? selectedYear + 1 : selectedYear
nextMonthCountDay += 1
this.$set(this.dateArr[weekIndex], dayIndex, {
date: new Date(nextYear, nextMonth, nextMonthCountDay),
status: {
isCurr: false,
isPrev: false,
isNext: true,
isWeekend: isWeekend(
new Date(nextYear, nextMonth, nextMonthCountDay)
)
}
})
}
}
}
}
while (
getDateMonth(this.dateArr[this.dateArr.length - 1][0].date) !==
selectedMonth
) {
// 某些月份不用六个星期 去除不需要的数据
this.dateArr.pop()
}
},
部分样式处理
就是根据item里面的状态进行动态class处理
handleDayClass(item, dayIndex, weekIndex) {
let classStr = `${
item.status.isWeekend || item.status.isNext || item.status.isPrev
? ' day_prev_next_weekend'
: ''
}${
dayjs(item.date).isSame(dayjs(this.currDate), 'day') ? ' day_curr' : ''
}${
dayIndex === this.clickDayIndex && weekIndex === this.clickWeekIndex
? ' day_active'
: ''
}`
return classStr
}
然后那个弹窗就是用vant组件的van-popover
,然后再初始化的时候给每一个item设置一个值与对应组件绑定,记得用$set
,不然数据可能是视图不对应。
具体代码就放在gitee仓库了,github网络写的时候用不了,后续需要再弄到github吧。
好累,好想回老家混吃等死,但是老家又没有前端行业职位,转行又不知道做什么~~~
转载自:https://juejin.cn/post/7173485766570409992