}
    },
    // 是否显示农历
    lunar: {
        type: Boolean,
        default: false
    },

    // 自定义星期名称
    weeks: {
        type: Array,
        default:function(){
            return window.navigator.language.toLowerCase() == "zh-cn"?['日', '一', '二', '三', '四', '五', '六']:['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
        }
    },
    // 自定义月份
    months:{
        type: Array,
        default:function(){
            return window.navigator.language.toLowerCase() == "zh-cn"?['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']:['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
        }
    },
    // 自定义事件
    events:  {
        type: Object,
        default: function(){
            return {}
        }
    },
},
data() {
    return {
        years:[],
        yearsShow:false,
        year: 0,
        month: 0,
        day: 0,
        days: [],
        multiDays:[],
        today: [],
        festival:{
            lunar:{
                "1-1":"春节",
                "1-15":"元宵节",
                "2-2":"龙头节",
                "5-5":"端午节",
                "7-7":"七夕节",
                "7-15":"中元节",
                "8-15":"中秋节",
                "9-9":"重阳节",
                "10-1":"寒衣节",
                "10-15":"下元节",
                "12-8":"腊八节",
                "12-23":"祭灶节",
            },
            gregorian:{
                "1-1":"元旦",
                "2-14":"情人节",
                "3-8":"妇女节",
                "3-12":"植树节",
                "4-5":"清明节",
                "5-1":"劳动节",
                "5-4":"青年节",
                "6-1":"儿童节",
                "7-1":"建党节",
                "8-1":"建军节",
                "9-10":"教师节",
                "10-1":"国庆节",
                "12-24":"平安夜",
                "12-25":"圣诞节",
            },
        },
        rangeBegin:[],
        rangeEnd:[],
    }
},
watch:{
    events(){
        this.render(this.year,this.month)
    },
    value(){
        this.init();
    }
},
mounted() {
    this.init()
},
methods: {
    init(){
        if (this.month === 0) {
            let now = new Date();
            this.year = now.getFullYear()
            this.month = now.getMonth()
            this.day = now.getDate()

        } else {
            if (this.value.length>0) {
                if (this.range) { //范围
                    this.year = parseInt(this.value[0][0])
                    this.month = parseInt(this.value[0][1]) - 1
                    this.day = parseInt(this.value[0][2]) 

                    let year2 = parseInt(this.value[1][0])
                    let month2 = parseInt(this.value[1][1]) - 1
                    let day2 = parseInt(this.value[1][2]) 

                    this.rangeBegin = [this.year, this.month,this.day]
                    this.rangeEnd = [year2, month2 , day2]
                }else if(this.multi){//多选
                    this.multiDays=this.value;
                    this.year = parseInt(this.value[0][0])
                    this.month = parseInt(this.value[0][1]) - 1
                    this.day = parseInt(this.value[0][2]) 
                }else{ //单选
                    this.year = parseInt(this.value[0])
                    this.month = parseInt(this.value[1]) - 1
                    this.day = parseInt(this.value[2]) 
                }
            }  
        }
        this.render(this.year, this.month)
    },
    // 渲染日期
    render(y, m) {
        let firstDayOfMonth = new Date(y, m, 1).getDay()         //当月第一天
        let lastDateOfMonth = new Date(y, m + 1, 0).getDate()    //当月最后一天
        let lastDayOfLastMonth = new Date(y, m, 0).getDate()     //最后一月的最后一天
        this.year = y
        let seletSplit = this.value
        let i, line = 0,temp = [],nextMonthPushDays = 1
        for (i = 1; i <= lastDateOfMonth; i++) {
            let day = new Date(y, m, i).getDay() //返回星期几(0~6)
            let k
            // 第一行
            if (day == 0) {
                temp[line] = []
            } else if (i == 1) {
                temp[line] = []
                k = lastDayOfLastMonth - firstDayOfMonth + 1
                for (let j = 0; j < firstDayOfMonth; j++) {
                    // console.log("第一行",lunarYear,lunarMonth,lunarValue,lunarInfo)
                    temp[line].push(Object.assign(
                        {day: k,disabled: true},
                        this.getLunarInfo(this.computedPrevYear(),this.computedPrevMonth(true),k),
                        this.getEvents(this.computedPrevYear(),this.computedPrevMonth(true),k),
                    ))
                    k++;
                }
            }
   
            
            if (this.range) { // 范围
                // console.log("日期范围",this.getLunarInfo(this.year,this.month+1,i))
                let options = Object.assign(
                    {day: i},
                    this.getLunarInfo(this.year,this.month+1,i),
                    this.getEvents(this.year,this.month+1,i),
                 )
                if (this.rangeBegin.length > 0) {
                    let beginTime = Number(new Date(this.rangeBegin[0], this.rangeBegin[1], this.rangeBegin[2]))
                    let endTime = Number(new Date(this.rangeEnd[0], this.rangeEnd[1], this.rangeEnd[2]))
                    let stepTime = Number(new Date(this.year, this.month, i))
                    if (beginTime <= stepTime && endTime >= stepTime) {
                        options.selected = true
                    }
                }
                if (this.begin.length>0) {
                    let beginTime = Number(new Date(parseInt(this.begin[0]),parseInt(this.begin[1]) - 1,parseInt(this.begin[2])))
                    if (beginTime > Number(new Date(this.year, this.month, i))) options.disabled = true
                }
                if (this.end.length>0){
                    let endTime = Number(new Date(parseInt(this.end[0]),parseInt(this.end[1]) - 1,parseInt(this.end[2])))
                    if (endTime <  Number(new Date(this.year, this.month, i))) options.disabled = true
                }
                if (this.disabled.length>0){
                    if (this.disabled.filter(v => {return this.year === v[0] && this.month === v[1]-1 && i === v[2] }).length>0) {
                        options.disabled = true
                    }
                }
                temp[line].push(options)
            }else if(this.multi){//多选
                let options
                // 判断是否选中
                if(this.value.filter(v => {return this.year === v[0] && this.month === v[1]-1 && i === v[2] }).length>0 ){
                    options = Object.assign({day: i,selected:true},this.getLunarInfo(this.year,this.month+1,i),this.getEvents(this.year,this.month+1,i))
                }else{
                    options = Object.assign({day: i,selected:false},this.getLunarInfo(this.year,this.month+1,i),this.getEvents(this.year,this.month+1,i))
                    if (this.begin.length>0) {
                        let beginTime = Number(new Date(parseInt(this.begin[0]),parseInt(this.begin[1]) - 1,parseInt(this.begin[2])))
                        if (beginTime > Number(new Date(this.year, this.month, i))) options.disabled = true
                    }
                    if (this.end.length>0){
                        let endTime = Number(new Date(parseInt(this.end[0]),parseInt(this.end[1]) - 1,parseInt(this.end[2])))
                        if (endTime <  Number(new Date(this.year, this.month, i))) options.disabled = true
                    }
                    if (this.disabled.length>0){
                        if (this.disabled.filter(v => {return this.year === v[0] && this.month === v[1]-1 && i === v[2] }).length>0) {
                            options.disabled = true
                        }
                    }
                }
                
                temp[line].push(options)
            } else { // 单选
                 // console.log(this.lunar(this.year,this.month,i));
                
                let chk = new Date()
                let chkY = chk.getFullYear()
                let chkM = chk.getMonth()
                // 匹配上次选中的日期
                if (parseInt(seletSplit[0]) == this.year && parseInt(seletSplit[1]) - 1 == this.month && parseInt(seletSplit[2]) == i) {
                    // console.log("匹配上次选中的日期",lunarYear,lunarMonth,lunarValue,lunarInfo)
                    temp[line].push(Object.assign(
                        {day: i,selected: true},
                        this.getLunarInfo(this.year,this.month+1,i),
                        this.getEvents(this.year,this.month+1,i),
                    ))
                    this.today = [line, temp[line].length - 1]
                }
                 // 没有默认值的时候显示选中今天日期
                else if (chkY == this.year && chkM == this.month && i == this.day && this.value == "") {

                    // console.log("今天",lunarYear,lunarMonth,lunarValue,lunarInfo)
                    temp[line].push(Object.assign(
                        {day: i,selected: true},
                        this.getLunarInfo(this.year,this.month+1,i),
                        this.getEvents(this.year,this.month+1,i),
                    ))
                    this.today = [line, temp[line].length - 1]
                }else{
                    // 普通日期
                    // console.log("设置可选范围",i,lunarYear,lunarMonth,lunarValue,lunarInfo)
                    let options = Object.assign(
                        {day: i,selected:false},
                        this.getLunarInfo(this.year,this.month+1,i),
                        this.getEvents(this.year,this.month+1,i),
                    )
                    if (this.begin.length>0) {
                        let beginTime = Number(new Date(parseInt(this.begin[0]),parseInt(this.begin[1]) - 1,parseInt(this.begin[2])))
                        if (beginTime > Number(new Date(this.year, this.month, i))) options.disabled = true
                    }
                    if (this.end.length>0){
                        let endTime = Number(new Date(parseInt(this.end[0]),parseInt(this.end[1]) - 1,parseInt(this.end[2])))
                        if (endTime <  Number(new Date(this.year, this.month, i))) options.disabled = true
                    }
                    if (this.disabled.length>0){
                        if (this.disabled.filter(v => {return this.year === v[0] && this.month === v[1]-1 && i === v[2] }).length>0) {
                            options.disabled = true
                        }
                    }
                    temp[line].push(options)
                }
            }
            // 到周六换行
            if (day == 6 && i < lastDateOfMonth) {
                line++
            }else if (i == lastDateOfMonth) {
                // line++
                let k = 1
                for (let d=day; d < 6; d++) {
                     // console.log(this.computedNextYear()+"-"+this.computedNextMonth(true)+"-"+k)
                    temp[line].push(Object.assign(
                        {day: k,disabled: true},
                        this.getLunarInfo(this.computedNextYear(),this.computedNextMonth(true),k),
                        this.getEvents(this.computedNextYear(),this.computedNextMonth(true),k),
                    ))
                    k++
                }
                // 下个月除了补充的前几天开始的日期
                nextMonthPushDays=k
            }
        } //end for

        // console.log(this.year+"/"+this.month+"/"+this.day+":"+line)
        // 补充第六行让视觉稳定
        // if(line<=5 && nextMonthPushDays>0){
        //     // console.log({nextMonthPushDays:nextMonthPushDays,line:line})
        //     for (let i = line+1; i<=5; i++) {
        //         temp[i] = []
        //         let start=nextMonthPushDays+(i-line-1)*7
        //         for (let d=start; d <= start+6; d++) {
        //             temp[i].push(Object.assign(
        //                 {day: d,disabled: true},
        //                 this.getLunarInfo(this.computedNextYear(),this.computedNextMonth(true),d),
        //                 this.getEvents(this.computedNextYear(),this.computedNextMonth(true),d),
        //             ))
        //         }  
        //     }
        // }
        this.days = temp
    },
    computedPrevYear(){
        let value=this.year
        if(this.month-1<0){
            value--
        }
        return value
    },
    computedPrevMonth(isString){
        let value=this.month
        if(this.month-1<0){
            value=11
        }else{
            value--
        }
        // 用于显示目的(一般月份是从0开始的)
        if(isString){
            return value+1
        }
        return value
    },
    computedNextYear(){
        let value=this.year
        if(this.month+1>11){
            value++
        }
        return value
    },
    computedNextMonth(isString){
        let value=this.month
        if(this.month+1>11){
            value=0
        }else{
            value++
        }
        // 用于显示目的(一般月份是从0开始的)
        if(isString){
            return value+1
        }
        return value
    },
    // 获取农历信息
    getLunarInfo(y,m,d){
        let lunarInfo=calendar.solar2lunar(y,m,d)
        let lunarValue=lunarInfo.IDayCn
        // console.log(lunarInfo)
        let isLunarFestival=false
        let isGregorianFestival=false
        if(this.festival.lunar[lunarInfo.lMonth+"-"+lunarInfo.lDay]!=undefined){
            lunarValue=this.festival.lunar[lunarInfo.lMonth+"-"+lunarInfo.lDay]
            isLunarFestival=true
        }else if(this.festival.gregorian[m+"-"+d]!=undefined){
            lunarValue=this.festival.gregorian[m+"-"+d]
            isGregorianFestival=true
        }
        return {
            lunar:lunarValue,
            isLunarFestival:isLunarFestival,
            isGregorianFestival:isGregorianFestival,
        }
    },
    // 获取自定义事件
    getEvents(y,m,d){
        if(Object.keys(this.events).length==0)return false;
        let eventName=this.events[y+"-"+m+"-"+d]
        let data={}
        if(eventName!=undefined){
            data.eventName=eventName
        }
        return data
    },
    // 上月
    prev(e) {
        e.stopPropagation()
        if (this.month == 0) {
            this.month = 11
            this.year = parseInt(this.year) - 1
        } else {
            this.month = parseInt(this.month) - 1
        }
        this.render(this.year, this.month)
        this.$emit('selectMonth',this.month+1,this.year)
        this.$emit('prev',this.month+1,this.year)
        this.$emit('currentYearMon',this.year, this.month+1)
    },
    //  下月
    next(e) {
        
        e.stopPropagation()
        if (this.month == 11) {
            this.month = 0
            this.year = parseInt(this.year) + 1
        } else {
            this.month = parseInt(this.month) + 1
        }
        this.render(this.year, this.month)
        this.$emit('selectMonth',this.month+1,this.year)
        this.$emit('next',this.month+1,this.year)

        this.$emit('currentYearMon', this.year, this.month+1)
    },
    // 选中日期
    select(k1, k2, e) {
        if (e != undefined) e.stopPropagation()
            // 日期范围
        if (this.range) {
            if (this.rangeBegin.length == 0 || this.rangeEndTemp != 0) {
                this.rangeBegin = [this.year, this.month,this.days[k1][k2].day]
                this.rangeBeginTemp = this.rangeBegin
                this.rangeEnd = [this.year, this.month, this.days[k1][k2].day]
                this.rangeEndTemp = 0
                
            } else {
                this.rangeEnd = [this.year, this.month,this.days[k1][k2].day]
                this.rangeEndTemp = 1
                    // 判断结束日期小于开始日期则自动颠倒过来
                if (+new Date(this.rangeEnd[0], this.rangeEnd[1], this.rangeEnd[2]) < +new Date(this.rangeBegin[0], this.rangeBegin[1], this.rangeBegin[2])) {
                    this.rangeBegin = this.rangeEnd
                    this.rangeEnd = this.rangeBeginTemp
                }
                // 小于10左边打补丁
                let begin=[]
                let end=[]
                if(this.zero){
                    this.rangeBegin.forEach((v,k)=>{
                        if(k==1)v=v+1
                        begin.push(this.zeroPad(v))
                    })
                    this.rangeEnd.forEach((v,k)=>{
                        if(k==1)v=v+1
                        end.push(this.zeroPad(v))
                    })
                }else{
                    begin=this.rangeBegin
                    end=this.rangeEnd
                }
                // console.log("选中日期",begin,end)
                this.$emit('select',begin,end)
            }
            this.render(this.year, this.month)
        }else if (this.multi) {
            // 如果已经选过则过滤掉
            let filterDay=this.multiDays.filter(v => {
              return this.year === v[0] && this.month === v[1]-1 && this.days[k1][k2].day === v[2]
            })
            if( filterDay.length>0 ){
                this.multiDays=this.multiDays.filter(v=> {
                  return this.year !== v[0] || this.month !== v[1]-1 || this.days[k1][k2].day !== v[2]
                })
            }else{
                this.multiDays.unshift([this.year,this.month+1,this.days[k1][k2].day]);
                // this.multiDays.push([this.year,this.month+1,this.days[k1][k2].day]);
            }
            this.days[k1][k2].selected = !this.days[k1][k2].selected
            this.$emit('select',this.multiDays)
            this.$emit('currentYearMon',this.year, this.month+1)
        } else {
            // 取消上次选中
            if (this.today.length > 0) {
                this.days.forEach(v=>{
                    v.forEach(vv=>{
                        vv.selected= false
                    })
                })
            }
            // 设置当前选中天
            this.days[k1][k2].selected = true
            this.day = this.days[k1][k2].day
            this.today = [k1, k2]
            this.$emit('select',[this.year,this.zero?this.zeroPad(this.month + 1):this.month + 1,this.zero?this.zeroPad(this.days[k1][k2].day):this.days[k1][k2].day])
            this.$emit('currentYearMon',this.year, this.month+1)
        }
    },
    changeYear(){
        if(this.yearsShow){
            this.yearsShow=false
            return false
        }
        this.yearsShow=true
        this.years=[];
        for(let i=~~this.year-10;i<~~this.year+10;i++){
            this.years.push(i)
        }
    },
    selectYear(value){
        this.yearsShow=false
        this.year=value
        this.render(this.year,this.month)
        this.$emit('selectYear',value)
        this.$emit('currentYearMon',this.year, this.month+1)
    },
    // 返回今天
    setToday(){
        let now = new Date();
        this.year = now.getFullYear()
        this.month = now.getMonth()
        this.day = now.getDate()
        this.render(this.year,this.month)
        // 遍历当前日找到选中
        this.days.forEach(v => {
            let day=v.find(vv => {
                return vv.day==this.day && !vv.disabled
            })
            if(day!=undefined ){
              day.selected=true  
            }
            
        })
    },
    // 日期补零
    zeroPad(n){
        return String(n < 10 ? '0' + n : n)
    },
    // 根据年月,获取整月的日期 
    getFullMonth() {
        let daysCount = new Date(this.year, this.month + 1, 0).getDate() 
        var dateArray = []; 
            for(var i= 1; i <= daysCount; i++) {
	                let _date = [this.year,this.month + 1, i]
	                dateArray.push(_date)
            }
        return dateArray
    },
    // 当月全选
    chooseAll() {
        if (this.multi) {
            // 当前所有月
            let fullMonth = this.getFullMonth() 
             // 非当前月所有天
            let filterDay = this.multiDays.filter(v => {
                return !(this.year === v[0] && this.month + 1 === v[1])
            })
            // this.multiDays = fullMonth.concat(filterDay)
            this.multiDays = fullMonth 
            this.$emit('select',this.multiDays)
            this.$emit('currentYearMon',this.year, this.month+1)
        }
    },
    //当月反选
    chooseReverse(){
         if (this.multi) {
            // 当前所有月
            let fullMonth = this.getFullMonth() 
            // 非当前月所有天
            let filterDay = this.multiDays.filter(v => {
                return !(this.year === v[0] && this.month + 1 === v[1])
            })
            // 当前月所选中天
            let currentSelect = this.multiDays.filter(v => {
                return (this.year === v[0] && this.month + 1 === v[1])
            })
            // 从当前月去掉当前选中状态的日期
            let reverse = []
            let _fullMonth = []

            fullMonth.map(v =>  _fullMonth.push(v[2]))
            currentSelect.map(v => {
                _fullMonth.map(full => {
                    if (v[2] === full) {
                       let index = _fullMonth.indexOf(v[2])
                       _fullMonth.splice(index, 1)
                    } 
                })
            })
            _fullMonth.map(v => reverse.push([this.year, this.month + 1, v]) )
            // this.multiDays = reverse.concat(filterDay)
            this.multiDays = reverse
            // console.log('this.multiDays',this.multiDays, this.year,this.month);
            this.$emit('select',this.multiDays)
            this.$emit('currentYearMon',this.year, this.month+1)
            //  this.render(this.year,this.month)
         }
    }
}

}

.calendar-tools{
height:40px;
font-size: 20px;
line-height: 40px;
color:#5e7a88;
border-bottom: 1px solid #e8eaec;
}
.calendar-tools span{
cursor: pointer;
}
.calendar-prev{
width: 14.28571429%;
float:left;
text-align: center;
}
.calendar-info{
padding-top: 3px;
font-size:16px;
line-height: 1.3;
text-align: center;
}
.calendar-info>div.month{
margin:auto;
height:20px;
width:100px;
text-align: center;
color:#5e7a88;
overflow: hidden;
position: relative;
}
.calendar-info>div.month .month-inner{
position: absolute;
left:0;
top:0;
height:240px;
transition:top .5s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.calendar-info>div.month .month-inner>span{
display: block;
font-size: 14px;
height:20px;
width:100px;
overflow: hidden;
text-align: center;
}
.calendar-info>div.year{
font-size:10px;
line-height: 1;
color:#999;
}
.calendar-next{
width: 14.28571429%;
float:right;
text-align: center;
}

.calendar table {
clear: both;
width: 100%;
margin-bottom:10px;
border-collapse: collapse;
color: #444444;
}
.calendar table thead td{
line-height: 24px;
text-align: center;
margin: 2px !important;
/* color: #c5c8ce; */
padding: 10px 0;
font-size:16px !important;
font-weight: bold;
}
.calendar td {
margin:2px !important;
padding:0px 0;
width: 14.28571429%;
height:44px;
text-align: center;
vertical-align: middle;
font-size:14px;
line-height: 125%;
cursor: pointer;
position: relative;
vertical-align: top;
}
.calendar td.week{
font-size:10px;
pointer-events:none !important;
cursor: default !important;
}
.calendar td.disabled {
color: #ccc;
pointer-events:none !important;
cursor: default !important;
}
.calendar td.disabled div{
color: #ccc;
}
.calendar td span{
display:block;
max-width:40px;
height:26px;
font-size: 16px;
line-height:26px;
margin:0px auto;
border-radius:20px;
}
.calendar td:not(.selected) span:not(.red):hover{

最后

本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端视频资料:
efault !important;
}
.calendar td.disabled {
color: #ccc;
pointer-events:none !important;
cursor: default !important;
}
.calendar td.disabled div{
color: #ccc;
}
.calendar td span{
display:block;
max-width:40px;
height:26px;
font-size: 16px;
line-height:26px;
margin:0px auto;
border-radius:20px;
}
.calendar td:not(.selected) span:not(.red):hover{

最后

本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

[外链图片转存中…(img-BbqDdQlN-1714374059056)]

前端视频资料:

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐