m-simple-calendar
Version:
239 lines (224 loc) • 5.93 kB
JavaScript
import { ref, watch, computed, useTemplateRef, nextTick } from 'vue'
/**
* 加 0 补位
*/
const addZero = value => (value < 10 ? `0${value}` : `${value}`)
/**
* 获取一个月有多少天
* 原理: 获取一个月的最后一天天数即获得一个月有多少天
* @param { number } y 年份
* @param { number } m 月份,1 表示一月
* new Date(2025, 2, 0) -> 2025 3 月的第 0 天表示 2 月的最后一天
*/
const getMonthDay = (y, m) => new Date(y, m, 0).getDate()
export const useShow = ({ visible }, initData) => {
/**
* 销毁开关
*/
const destroy = ref(false)
const showAnimation = ref(false)
const calendarRef = useTemplateRef('calendarRef')
let timerRef
const findCalendarRef = (count = 0) => {
return new Promise((resolve, reject) => {
if (count > 50) {
reject(new Error('获取错误'))
return
}
clearTimeout(timerRef)
timerRef = setTimeout(() => {
if (calendarRef.value) {
resolve(true)
} else {
findCalendarRef(count + 1)
}
}, 100)
})
}
watch(
visible,
bool => {
if (bool) {
initData()
destroy.value = true
findCalendarRef().then(() => {
showAnimation.value = true
})
} else {
showAnimation.value = false
setTimeout(() => {
destroy.value = false
}, 300)
}
},
{ immediate: true }
)
const onClose = () => {
visible.value = false
}
return { showAnimation, destroy, onClose }
}
/**
* 操作
*/
export const useHandle = ({ props, emit, modelValue, visible }) => {
const curDate = ref({
y: 0,
m: 0,
d: 0
})
const getStyle = computed(() => {
const style = props.style || {}
let option = {}
if (typeof style === 'string') {
style.split(';').map(item => {
const [key, value] = item.split(':')
key && (option[key] = value)
})
} else {
option = style
}
return {
...option,
'--theme': props.themeColor || '#409eff'
}
})
/**
* 星期中文
*/
const week = Object.freeze(['日', '一', '二', '三', '四', '五', '六'])
/**
* 月份中文
*/
const monthCn = Object.freeze(['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'])
/**
* 展示信息
*/
const dateInfo = computed(() => ({
y: curDate.value.y,
m: monthCn[curDate.value.m - 1]
}))
/**
* 总展示天数, 6 排 7 列
*/
const total = 6 * 7
/**
* 初始化数据
*/
const initData = () => {
/**
* 当前时间
*/
const now = new Date()
const nowDate = `${now.getFullYear()}-${addZero(now.getMonth() + 1)}-${addZero(now.getDate())}`
/**
* 目标时间
*/
const date = modelValue.value ? new Date(modelValue.value) : new Date()
const curDays = []
const [y, m, d] = [date.getFullYear(), date.getMonth() + 1, date.getDate()]
modelValue.value && (modelValue.value = `${y}-${addZero(m)}-${addZero(d)}`)
/**
* 当月开始星期
*/
const startW = new Date(`${y}-${m}-1`).getDay()
let nm = m - 1
let ny = y
if (nm === 0) {
nm = 12
ny--
}
/**
* 上月总天数
*/
const prevTotalDay = getMonthDay(ny, nm)
Array.from({ length: startW }, (_, i) => {
const newDay = prevTotalDay - i
const tempDate = `${ny}-${nm}-${newDay}`
curDays.push({ y: ny, m: nm, d: newDay, value: addZero(newDay), disabled: true, today: tempDate === nowDate })
})
/**
* 当月总天数
*/
const totalDay = getMonthDay(y, m)
Array.from({ length: totalDay }, (_, i) => {
const nd = i + 1
const tempDate = `${y}-${addZero(m)}-${addZero(nd)}`
const today = tempDate === nowDate
const selected = modelValue.value ? tempDate === modelValue.value : false
curDays.push({ y, m, d: nd, value: addZero(nd), today, selected })
})
/**
* 下月
*/
let nextM = m + 1
let nextY = y
if (nextM > 12) {
nextM = 1
nextY++
}
Array.from({ length: total - curDays.length }, (_, i) => {
const nd = i + 1
const tempDate = `${nextY}-${nextM}-${nd}`
curDays.push({ y: nextY, m: nextM, d: nd, value: addZero(nd), disabled: true, today: tempDate === nowDate })
})
days.value = curDays
curDate.value = { y, m, d }
}
/**
* 展示所有时间
*/
const days = ref([])
/**
* 箭头处理
*/
const handleYearMonth = (y, m, d) => {
const totalDay = getMonthDay(y, m)
d > totalDay && (d = totalDay)
modelValue.value = `${y}-${addZero(m)}-${addZero(d)}`
nextTick(initData)
}
/**
* 点击双向箭头-年
*/
const onYearItem = calc => {
const { y, m, d } = curDate.value
const ny = y + calc
handleYearMonth(ny, m, d)
}
/**
* 点击单向箭头-月
*/
const onMonthItem = calc => {
let { y, m, d } = curDate.value
m += calc
d = +d
if (m > 12) {
m = 1
y++
} else if (m === 0) {
m = 12
y--
}
handleYearMonth(y, m, d)
}
/**
* 点击天数-天
*/
const onDayItem = (item, index) => {
if (item.selected) return
modelValue.value = `${item.y}-${addZero(item.m)}-${addZero(item.d)}`
props.closable && (visible.value = false)
if (item.disabled) {
nextTick(initData)
return
}
days.value.forEach((day, i) => {
day.selected = i === index
})
}
watch(modelValue, value => {
emit('change', value)
})
return { getStyle, week, dateInfo, days, onYearItem, onMonthItem, onDayItem, initData }
}