<template>
<div v-click-outside>
<input type="text" :value="formatDate">
<div v-if="isVisible" class="pannel">
<div class="pannel-nav">
<span @click="prevYear"><</span>
<span @click="prevMonth"><<</span>
<span>{{time.year}}年</span>
<span>{{time.month + 1}}月</span>
<span @click="nextMonth">>></span>
<span @click="nextYear">></span>
</div>
<div class="pannel-content">
<span v-for="(item,index) in week">{{item}}</span>
<div class="days">
<div v-for="i in 6" :key="i">
<!--判断是不是当月,不是就变灰-->
<span
v-for="j in 7" :key="j"
@click="handleChooseDate(visibleDays[(i-1) * 7 + (j-1)])"
class="cell"
:class="[
{notCurrerntMonth:!isCurrerntMonth(visibleDays[(i-1) * 7 + (j-1)])},
{today: isToday(visibleDays[(i-1) * 7 + (j-1)])},
{select: isSelect(visibleDays[(i-1) * 7 + (j-1)])}
]"
>
{{visibleDays[(i-1) * 7 + (j-1)].getDate()}}
</span>
</div>
</div>
</div>
<div class="pannel-footer">
今天
</div>
</div>
</div>
</template>
<script>
// 日历组件
export default {
name: 'Calendar',
// https://www.cnblogs.com/moqiutao/p/8334780.html
directives: {
clickOutside: { // 指令得生命周期
// el: 指令所绑定的元素,可以用来直接操作DOM。
// binding: 一个对象,包含指令的很多信息。
// vnode: Vue编译生成的虚拟节点。
bind(el,bindings,vnode) { // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
// 把时间绑定给document上,看一下点击得是否是当前的这个元素内部
let handler = (e) => {
// console.log(e.target)
if(el.contains(e.target)) { // el.contains(e.target) 原生dom操作
// 判断下日历面板是否已显示
if(!vnode.context.isVisible) {
vnode.context.hanldeFocus()
}
}else {
if(vnode.context.isVisible) {
vnode.context.handleBlur()
}
}
}
el.handler = handler
document.addEventListener('click',handler)
},
unbind(el){
document.removeEventListener('click',el.handler)
}
}
},
data () {
let {year, month} = this.getYearMonthDay(this.value)
return {
week: ['日', '一', '二', '三', '四', '五', '六'],
time: {year,month},
isVisible: false // 控制日历面板是否可见
}
},
props: {
value: {
type: Date,
default: () => new Date() // 对象,数组返回的默认值必须是一个对象
}
},
mounted() {
console.log(this.visibleDays)
},
computed: {
visibleDays() {
let {year,month} = this.getYearMonthDay(this.getDate(this.time.year,this.time.month, 1))
// 获取当前月份第一天
let currentFirstDay = this.getDate(year,month,1)
// 获取第一天是周几
let week = currentFirstDay.getDay()
console.log('week',week)
// 计算当月开始的天数
let startDay = currentFirstDay - week * 60 * 60 * 1000 * 24
// 循环42天
let arr = []
for(let i = 0; i < 42; i++) {
arr.push(new Date(startDay + i * 60 * 60 * 1000 * 24))
}
return arr
},
formatDate() {
let {year,month,day} = this.getYearMonthDay(this.value)
return `${year}-${month + 1}-${day}`
}
},
methods:{
// 获取年月日
getYearMonthDay() {
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
return {year, month, day}
},
getDate(year, month, day) {
return new Date(year, month, day)
},
hanldeFocus() {
this.isVisible = true // 显示面板
},
handleBlur() {
this.isVisible = false // 隐藏面板
},
// 是否当月
isCurrerntMonth(date) {
// 传入值匹配当前年月
let {year,month} = this.getYearMonthDay(this.getDate(this.time.year,this.time.month,1))
let {year:y, month:m} = this.getYearMonthDay(date);
return year === y && month === m
},
// 是否今天
isToday(date) {
let {year,month,day} = this.getYearMonthDay(new Date())
let {year:y, month:m, day:d} = this.getYearMonthDay(date)
return year === y && month === m && day === d
},
// 改变input value
handleChooseDate(date) {
this.time = this.getYearMonthDay(date)
this.$emit('change',date)
this.handleBlur() // 关闭日历模板
},
// 是否被选中
isSelect(date) {
let {year,month,day} = this.getYearMonthDay(this.value)
let {year:y, month:m, day:d} = this.getYearMonthDay(date)
return year === y && month === m && day === d
},
// 上一个月
prevMonth() {
let d = this.getDate(this.time.year,this.time.month,1)
d.setMonth(d.getMonth()-1)
this.time = this.getYearMonthDay(d)
},
// 下一个月
nextMonth() {
let d = this.getDate(this.time.year,this.time.month,1)
d.setMonth(d.getMonth() + 1)
this.time = this.getYearMonthDay(d)
},
// 上一年
prevYear() {
let d = this.getDate(this.time.year,this.time.month,1)
d.setFullYear(d.getFullYear() - 1)
this.time = this.getYearMonthDay(d)
},
// 下一年
nextYear() {
let d = this.getDate(this.time.year,this.time.month,1)
d.setFullYear(d.getFullYear() + 1)
this.time = this.getYearMonthDay(d)
}
}
}
</script>
<style scoped lang="less">
.pannel {
width: 32 * 7px;
position: absolute;
background: #fff;
margin-top: 10px;
box-shadow: 2px 2px 2px pink, -2px -2px 2px pink;
.pannel-nav {
display: flex;
justify-content: space-around;
height: 30px;
user-select: none;
span {
cursor: pointer;
}
}
.pannel-content {
span {
display: inline-flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
font-weight: bold;
box-sizing: border-box;
}
.cell {
cursor: pointer;
}
.cell:hover {
border: 1px solid pink;
}
.notCurrerntMonth {
color: gray;
}
.today {
background: red;
color: white;
}
.select {
background: pink;
color: white;
}
}
.pannel-footer {
height: 30px;
text-align: center;
}
}
</style>
网友评论