vue实现日历组件

MyCalender.vue

<template>
  <div>
    <div class="calender_header">
      <ul>
        <li v-for="(item,index) in weekDays" v-text="item" :key="index"></li>
      </ul>
    </div>
    <!--实现的基本思路:
        1.月份切换到周的变化:
                高度变化
                数据变化
    -->
    <!--遍历日历数组-->
    <div
      @touchstart.stop="moveStart"
      @touchend.stop="moveEnd"
      @touchmove.prevent="move"
      class="calender_outer">
      <div class="calender_father" ref="calenderFatherRef">
        <div v-for="(month,index) in dateList" :key="index" class="calender">
          <!--每周数据-->
          <ul v-for="(week,weekIndex) in month" :key="weekIndex">
            <!--每天数据-->
            <li @click.stop="(day.mode=='month'&&!day.isCurrentMonth)?'':togglePreCurrentDay(day)" v-for="(day,dayIndex) in week" :key="dayIndex">
              <div :class="{today:isToday(day.year,day.month,day.day),selected:isSelected(day.year,day.month,day.day),isCurrentMonth:day.mode=='month'&&!day.isCurrentMonth}">
                {{day.day}}
                <div v-show="initTotalSign(day.date)" class="circle"></div>
              </div>
            </li>
          </ul>
        </div>
      </div>
    </div>
    <div style="display: flex;align-items: center;justify-content: center;height: 20px;">
      <div v-show="mode=='week'" class="down" @click="toggleSwitch()"></div>
      <div v-show="mode=='month'" class="up" @click="toggleSwitch()"></div>
    </div>
  </div>
</template>

<script>
  import {get3month,get3week,GET_DATE_YEAR_MONTH_DAY} from './calender_bak'
  export default {
    name: "MyCalender",
    props:{
      meetingTotalMap:{
        type: Object,
        default: function () {
          return { }
        }
      },
    },
    data(){
      return {
        weekDays:['日', '一', '二', '三', '四', '五', '六'],//当前显示的周
        dateList:[],//日历数据
        mode:'week',//week,month
        current:{
          year:null,//年
          month:null,//月
          day:null//日
        },
        touchXY:{
          startX:0,//开始X坐标
          startY:0,//开始Y坐标
          endX:0,//结束X坐标
          endY:0,//结束Y坐标
          moveX:0,//x方向移动距离
          moveY:0,//x方向移动距离
        }//触摸发生参数
      }
    },
    methods:{
      initTargetDate(year,month,day){
        this.current={
          year:year,//年
          month:month,//月
          day:day//日
        }
        this.initData()
      },
      /*初始化数据*/
      initData(){
        const {year,month,day}=this.current;
        if(this.mode=='week'){
          this.dateList=get3week(year,month-1,day);//注意:month范围[0-11]
        }else{
          this.dateList=get3month(year,month-1);//注意:month范围[0-11]
        }
      },
      /*切换模式*/
      toggleSwitch(){
        if(this.mode=='week'){
          this.mode='month'
        }else{
          this.mode='week'
        }
      },
      /*上个月或周*/
      togglePreDate(){
        let {year,month,day}=this.current;
        if(this.mode=='week'){
          let obj=this.dateList[0][0][new Date(year,month-1,day).getDay()];
          year=obj.year;
          month=obj.month;
          day=obj.day;
        }else{
          //上个月
          if (month===1) {
            //上一年12月
            year=year-1;
            month=12;
          }else{
            month=month-1;
          }
          day=1;
        }
        this.current={
          year:year,//年
          month:month,//月
          day:day//日
        }
        this.initData();
      },
      /*下个月或周*/
      toggleNextDate(){
        let {year,month,day}=this.current;
        if(this.mode=='week'){
          let obj=this.dateList[2][0][new Date(year,month-1,day).getDay()];
          year=obj.year;
          month=obj.month;
          day=obj.day;
        }else{
          //下个月
          if (month===12) {
            //下一年1月
            year=year+1;
            month=1;
          }else{
            month=month+1;
          }
          day=1;
        }
        this.current={
          year:year,//年
          month:month,//月
          day:day//日
        }
        this.initData();
      },
      /*点击选中天*/
      togglePreCurrentDay(dayObj){
        const {year,month,day}=dayObj;
        this.current={ year:year,month:month,day:day }
      },
      /*事件触发*/
      moveStart(e){
        let touch;
        if(e.changedTouches){
          touch = e.changedTouches[0];
        }else{
          touch = e
        }
        this.touchXY.startX=touch.clientX;//开始触摸点X
        this.touchXY.startY=touch.clientY;//开始触摸点Y
      },
      move(e){
        let touch;
        if(e.changedTouches){
          touch = e.changedTouches[0];
        }else{
          touch = e
        }
        this.touchXY.endX=touch.clientX;//结束触摸点X
        this.touchXY.endY=touch.clientY;//结束触摸点Y
        this.touchXY.moveX=this.touchXY.endX-this.touchXY.startX//移动距离
        this.touchXY.moveY=this.touchXY.endY-this.touchXY.startY//移动距离
        if(Math.abs(this.touchXY.moveX)>Math.abs(this.touchXY.moveY)){
          let f=this.$refs['calenderFatherRef'];
          f.style.transform="translateX("+this.touchXY.moveX+"px)";
        }
      },
      moveEnd(e){
        let _this=this;
        const {startX,startY,endX,endY,moveX,moveY} =this.touchXY
        if(Math.abs(moveX)>10||Math.abs(moveY)>10){
          if(Math.abs(moveX)>Math.abs(moveY)){
            //X方向切换
            if(moveX>0){
              _this.togglePreDate()
            }else{
              _this.toggleNextDate()
            }
          }else{
            //Y方向切换
            if(moveY>0&&_this.mode=='week'){
              _this.toggleSwitch();
            }else if(moveY<0&&_this.mode=='month'){
              _this.toggleSwitch();
            }
          }
        }
        let f=this.$refs['calenderFatherRef'];
        f.style.transform="translateX("+0+"px)";
        this.touchXY=Object.assign({},this.$options.data.touchXY)
      },
    },
    created() {
      const [year,month,day]=GET_DATE_YEAR_MONTH_DAY();
      this.current={
        year:year,//年
        month:month,//月
        day:day//日
      }
      this.initData()
    },
    computed:{
      /*是否当前选中*/
      isSelected(){
        const {year,month,day}=this.current;
        return (year1,month1,day1)=>{
          return year1==year&&month1==month&&day1==day;
        }
      },
      /*是否今天*/
      isToday(){
        const [year1,month1,day1]=this.$GET_DATE_YEAR_MONTH_DAY();
        return (year,month,day)=>{
          return year1==year&&month1==month&&day1==day;
        }
      },
      /*初始化标记*/
      initTotalSign(){
        let map=this.meetingTotalMap;
        return (date)=>{
          if(map[date]&&map[date]>0){
            return true;
          }else{
            return false;
          }
        }
      },
      /*该行是否全是下个月的*/
      /*isOtherMonth(){
        let mode=this.mode;
        return (week)=>{
          if(mode=='month'){
            for(let day of week){
              if(day.isCurrentMonth){
                return true;
              }
            }
            return false;
          }
          return true;
        }
      }*/
    },
    watch:{
      /*监听:模式切换*/
      mode(val,oldVal) {
        this.initData()
      },
      /*监听选中改变*/
      current:{
        deep:true,
        handler:function (val,oldVal) {
          const {year,month,day}=val;
          const {year:yearOld,month:monthOld,day:dayOld}=oldVal;
          if((year+'-'+month)!=(yearOld+'-'+monthOld)){
            this.$emit('yearMonthChange',year,month);//年月改变
          }
          this.$emit('dateChange',year,month,day);//选中日期改变
        }
      }
    }
  }
</script>

<style scoped>
  /* 日历 */
  .calender_header ul {display: flex;box-shadow: -1px 0 2px #333333;}
  .calender_header li {flex: 1;height: 30px;text-align: center;line-height: 30px;font-size: 8px;}
  .calender_outer{position: relative;width: 100%;overflow: hidden;box-shadow: 1px 0 2px #333333;}
  .calender_father{position: relative;width: 300%;display: flex;left: -100%;}
  .calender {position: relative;width: 100%;}
  .calender ul {display: flex;}
  .calender li {flex:1;position: relative;height:50px;display: flex;align-items: center;justify-content: center;}
  .circle { width: 4px; height: 4px; border-radius: 50%; background-color: #2183FE; position: absolute; bottom: 6px; left: 44%;}
  .today{color:#2183FE;}
  .selected{ width:40px;height:40px;line-height:40px;border-radius: 50%;background: #2183FE;color: white;text-align: center;position: relative;}
  .selected .circle{background-color: #FFFFFF;}
  .isCurrentMonth {color:#f2f2f2!important;}
  /*css实现上下左右箭头*/
  .down{
    border-right: 2px solid #343c99;
    border-top: 2px solid #343c99;
    height: 10px;
    width: 10px;
    transform: rotate(135deg);
  }
  .up{
    border-left: 2px solid #343c99;
    border-bottom: 2px solid #343c99;
    height: 10px;
    width: 10px;
    transform: rotate(135deg);
    margin-top: 11px;
  }
</style>

calender_bak.js

/*注意:month范围[0-11]*/
function format(year, month, day) {
  month++;
  month < 10 && (month = "0" + month);
  day < 10 && (day = "0" + day);
  return year + "-" + month + "-" + day;
}
/*注意:month范围[0-11]*/
export function getMonth(year, month) {
  let monthArr = [];//月份日期数组
  let dtFirst = new Date(year, month, 1); //每个月第一天
  let dtLast = new Date(year, month + 1, 0); //每个月最后一天
  let monthLength = dtLast.getDate() - dtFirst.getDate() + 1;
  let space = (dtFirst.getDay()+ 7) % 7; //月历前面空格
  for (let i = -space; i < 36; i += 7) {
    let week = [];//每一周的数据(一行)
    for (let j = 0; j < 7; j++) {
      let day = i + j + 1;//日
      if (day > 0 && day <= monthLength) {
        week.push({
          mode: "month",
          day: day,
          year: year,
          month: month+1,
          date: format(year, month, day),
          isCurrentMonth:true,
        });
      } else {
        //其它月份
        let newdt = new Date(year, month, day);
        let years = newdt.getFullYear();
        let months = newdt.getMonth();
        let days = newdt.getDate();
        week.push({
          mode: "month",
          day: days,
          year: years,
          month: months+1,
          date: format(years, months, days),
          isCurrentMonth:false,
        });
      }
    }
    monthArr.push(week);
  }
  return monthArr;
}
/*注意:month范围[0-11]*/
export function getWeek(year, month, day) {
  let dt = new Date(year, month, day);
  let weekArr = [];
  let dtFirst = new Date(year, month, day - ((dt.getDay() + 6) % 7));//周一
  let week = [];
  //循环选中当天所在那一周的每一天
  for (let j = -1; j < 6; j++) {
    let newdt = new Date(
      dtFirst.getFullYear(),
      dtFirst.getMonth(),
      dtFirst.getDate() + j
    );
    let years = newdt.getFullYear();
    let months = newdt.getMonth();
    let days = newdt.getDate();
    week.push({
      mode: "week",
      day: days,
      year: years,
      month: months+1,
      date: format(years, months, days),
    });
  }
  weekArr.push(week);
  return weekArr;
}
/** 获取三月:上月、这月、下月;注意:month范围[0-11]*/
export function get3month(year, month){
  let monthList = [];
  if (month===0) {
    monthList.push(getMonth(year-1, 11));//上一年的十二月
  } else {
    monthList.push(getMonth(year, month - 1));
  }
  monthList.push(getMonth(year, month));
  if (month===11) {
    monthList.push(getMonth(year+1, 0));//获取下一年的1月的
  } else {
    monthList.push(getMonth(year, month + 1));
  }
  return monthList;
}
/** 获取三周:上周、这周、下周;注意:month范围[0-11]*/
export function get3week(year,month,day) {
  let monthList = [];
  monthList.push(getWeek(year, month, day - 7));
  monthList.push(getWeek(year, month, day));
  monthList.push(getWeek(year, month, day + 7));
  return monthList;
}

export function GET_DATE_YEAR_MONTH_DAY (){
      let d=new Date();
      let year=d.getFullYear();
      let month=d.getMonth() + 1;
      let day=d.getDate();
      return [year,month,day];
    }

使用效果Test.vue

<template>
  <div class="container">
    <div style="padding: 10px 12px;text-align: center;">{{dateStr}}</div>
    <my-calender ref="calenderRef" :meetingTotalMap="meetingTotalMap" @yearMonthChange="yearMonthChange" @dateChange="dateChange"></my-calender>
    <!--会议列表-->
    <div>
      <div style="flex: 1;overflow: auto;background: #FAFAFA;">
        <div v-for="(item,index) in 100" :key="index" style="padding: 10px 12px;background-color: #FFE7E7;margin: 10px;">{{item}}</div>
     </div>
    </div>
  </div>
</template>

<script>
  import MyCalender from '../../components/calender/MyCalender'
  export default {
    name: "Test",
    components:{
      MyCalender:MyCalender
    },
    data(){
      return {
        dateStr:'',//当前时间
        meetingTotalMap:{
			'2021-08-20':1
		},//标记
      }
    },
    methods:{
      //时间月份改变
      yearMonthChange(year,month){
        const strDate=year+"-"+(month<10?("0"+month):month)+"-01";
      },
      //选中日期改变
      dateChange(year,month,day){
        this.dateStr=year+"-"+(month<10?("0"+month):month)+"-"+(day<10?("0"+day):day);
      }
    }
  }
</script>

<style scoped>
  .container {
    height: 100vh;
    display: flex;
    flex-direction: column;
  }
  .container > div:last-child {
    flex: 1;
    min-height: 0;
    position: relative;
    display: flex;
    flex-direction: column;
  }
</style>

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值