美文网首页
vue中日期与日历联动组件(自定义日历组件)

vue中日期与日历联动组件(自定义日历组件)

作者: 随遇而安丶 | 来源:发表于2022-05-05 16:19 被阅读0次

    因为项目需要用到日历组件,没有找到适用的组件,只能无奈自己写一个了,达到项目使用所需的功能,同时保留了较高的扩展性。

    先贴上效果图

    screenshots.gif

    具体day的点击事件逻辑就不贴出来了,有需要的根据自己的项目需求加上click即可

    代码分享

    -父组件代码

    有使用到 elementui 的 el-button el-date-picker,照抄的同学记得下载依赖
    <template>
      <div>
        <div class="top clearfix">
          <div class="top-left fl">
            <div class="tlt clearfix">
              <span class="title1 fl">我的课表</span>
              <el-button class="fr ml10" type="primary">下载排课表</el-button>
              <div class="block fr">
                <el-date-picker
                  v-model="value"
                  type="month"
                  :clearable=false
                  format="yyyy年 MM月"
                  @change="changeDate()"
                  placeholder="查看月份">
                </el-date-picker>
              </div>
            </div>
            <Calendar :defaultMonth.sync='defaultMonth'></Calendar>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    import Calendar from '@/components/Calendar'
    
    export default {
      components:{Calendar},
      data() {
        return {
          value:'',
          defaultMonth:''
        }
      },
      methods: {
        changeDate(){
          this.defaultMonth = this.value
        }
      },
      created(){
        let time = new Date()
        this.value = time
        this.defaultMonth = time
      }
    }
    </script>
    
    <style lang="stylus" scoped>
    .clearfix::before,
    .clearfix::after {
      content: '';
      display: table;
      clear: both;
    }
    .fl{
      float:left;
    }
    .fr{
      float:right;
    }
    .title1{
      color: #333
      font-size: 20px;
      font-weight 900
    }
    .top-left
      height 750px
      width 70%
      background-color #fff
      padding:20px;
      border-radius: 10px;
      &>.tlt
        line-height 40px;
        padding-bottom:10px;
    </style>
    

    -子组件代码

    <template>
      <!-- 日历组件 -->
      <div class="calendar-box">
        <table class="calendar-table">
          <thead>
            <th class="fc-day-header">日</th>
            <th class="fc-day-header">一</th>
            <th class="fc-day-header">二</th>
            <th class="fc-day-header">三</th>
            <th class="fc-day-header">四</th>
            <th class="fc-day-header">五</th>
            <th class="fc-day-header">六</th>
          </thead>
          <tbody>
            <tr>
              <td 
                v-for="(item, index) in calendarData"
                :key="index"
                :style="{'height': height}"
                @click="clickDay(item)">
                <div class="includeContent"
                  :class="{
                    'include': item.include,
                    'active': defaultDate.indexOf(item.date)>-1
                  }"
                >
                  <slot name="day" :row="item">
                    <div class="day">
                      <span class="d_one">{{ item.day2 }}</span>
                      <span class="d_two" v-if="defaultDate.indexOf(item.date)>-1">课</span>
                      <span class="d_three" v-if="defaultDate.indexOf(item.date)>-1" v-text="courseList[defaultDate.indexOf(item.date)]"></span>
                    </div>
                  </slot>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </template>
    <script>
    export default {
      name: 'calendarBox',
      props: {
        type: {  // all 可选中显示的所有日期 portion 只能选中当前月份的数据
          type: String,
          default: 'portion'
        },
        defaultMonth: {  // 默认日期
          type: Date,
          default () {
            let year = new Date().getFullYear() // 当月年份
            let month = new Date().getMonth() + 1 // 当月月份
            return new Date(year, month - 1, 1)
          }
        },
        height: { //设置td高度
          type: String,
          default: '94px'
        }
      },
      data () {
        return {
          calendarData: [],
          activeData: null,
          defaultDate:['2022-4-1','2022-4-7','2022-4-13','2022-4-18','2022-4-26','2022-4-28','2022-5-5','2022-5-15','2022-5-18','2022-5-20','2022-5-21','2022-5-30'],
          courseList:['美术课','武器课','瑜伽课','音乐课','吃饭','睡觉','看电影','逛街','考试','答辩','毕业','结婚'],
          // allDate:[  //这里是模拟数据,一般是从后台接口获取而来,需要自己获取的时候拆分成 defaultDate 和 courseList
          //   {date:'2022-4-1',course:'美术课'},
          //   {date:'2022-4-7',course:'武器课'},
          //   {date:'2022-4-13',course:'瑜伽课'},
          //   {date:'2022-4-18',course:'音乐课'},
          //   {date:'2022-4-26',course:'吃饭'},
          //   {date:'2022-4-28',course:'睡觉'},
          //   {date:'2022-5-5',course:'看电影'},
          //   {date:'2022-5-13',course:'逛街'},
          //   {date:'2022-5-14',course:'毕业'},
          //   {date:'2022-5-20',course:'答辩'},
          //   {date:'2022-5-25',course:'结婚'},
          // ] 
        }
      },
      created () {
        this.getCalendarDay()
      },
      methods: {
        // 获取日历天数
        getCalendarDay () {
          let year = new Date(this.defaultMonth).getFullYear() // 当月年份
          let month = new Date(this.defaultMonth).getMonth() + 1 // 当月月份
          let days = new Date(year, month, 0).getDate() // 当月天数
    
          let prevYear = month === 1 ? (year - 1) : year // 上一年年份
          let prevMonth = month === 1 ? 12 : (month - 1) // 上月月份
          let prevDays = new Date(prevYear, prevMonth, 0).getDate() // 上一月天数
    
          let lastYear = month === 12 ? (year + 1) : year // 下一年年份
          let lastMonth = month === 12 ? 1 : (month + 1) // 下月月份
          // let lastDays = new Date(lastYear, lastMonth, 0).getDate() // 下一月天数
    
          let prevMonthArr = [] // 上月数据
          let nextMonthArr = [] // 下月数据
          let currentMonthArr = [] // 当月数据
          // 判断当月1号是星期几
          let firstDay = new Date(year, month - 1, 1).getDay()
          // 获取显示上月的数据
          for (let i = 0; i < firstDay; i++) {
            let day = prevDays - firstDay + (i + 1)
            let day2 = day >= 10 ? day : ('0' + day)
            let month2 = prevMonth >= 10 ? prevMonth : ('0' + prevMonth)
            prevMonthArr.push({
              year: prevYear,
              month: prevMonth,
              month2: month2,
              day: day,
              day2: day2,
              date: `${prevYear}-${prevMonth}-${day}`,
              date2: `${prevYear}-${month2}-${day2}`,
              include: false
            })
          }
          // 获取显示的下一月的数据
          for (let i = 0; i < (42 - firstDay - days); i++) {
            let day = i + 1
            let day2 = day >= 10 ? day : ('0' + day)
            let month2 = lastMonth >= 10 ? lastMonth : ('0' + lastMonth)
            nextMonthArr.push({
              year: lastYear,
              month: lastMonth,
              month2: month2,
              day: day,
              day2: day2,
              date: `${lastYear}-${lastMonth}-${day}`,
              date2: `${lastYear}-${month2}-${day2}`,
              include: false
            })
          }
          // 获取当月显示数据
          for (let i = 1; i <= days; i++) {
            let day2 = i >= 10 ? i : ('0' + i)
            let month2 = month >= 10 ? month : ('0' + month)
            currentMonthArr.push({
              year: year,
              month: month,
              month2: month2,
              day: i,
              day2: day2,
              date: `${year}-${month}-${i}`,
              date2: `${year}-${month2}-${day2}`,
              include: true
            })
          }
    
          this.calendarData = [...prevMonthArr, ...currentMonthArr, ...nextMonthArr]
        },
        // 设置默认值
        setDefaultValue (date) {
          if (!date) {
            this.activeData = null
            return
          }
          let year = new Date(date).getFullYear() // 当月年份
          let month = new Date(date).getMonth() + 1 // 当月月份
          let month2 = month >= 10 ? month : ('0' + month)
          let day = new Date(date).getDate()
          let day2 = day >= 10 ? day : '0' + day
          let row = {
            year: year,
            month: month,
            month2: month2,
            day: day,
            day2: day2,
            date: `${year}-${month}-${day}`,
            date2: `${year}-${month2}-${day2}`,
            include: true
          }
          this.clickDay(row)
        },
        clickDay (row) {
          if (this.type === 'portion' && !row.include) {
            this.$message.closeAll()
            this.$message({
              type: 'info',
              message: '只能选择当前月份的日期'
            })
            return
          }
          this.activeData = { ...row }
          this.$emit('click', { ...row })
          // console.log(this.activeData);
        }
      },
      watch: {
        defaultMonth(){
          this.setDefaultValue()
          this.getCalendarDay()
        }
      }
    }
    </script>
    <style lang="stylus" scoped>
    $blue = #0176F6
    .calendar-box {
      background-color #f6f6f6
      padding 10px;
      .calendar-table {
        width: 100%;
        border-radius: 4px;
        display: block;
        overflow: hidden;
        thead,
        tbody {
          display: flex;
          width: 100%;
        }
        tr {
          width: 100%;
        }
        th {
          height: 50px;
          line-height: 50px;
          text-align: center;
          color: #3E597B;
          box-sizing: border-box;
          display: inline-block;
          width: 14.28%;
        }
        td {
          width: 14.28%;
          display: inline-block;
          position: relative;
          font-size: 16px;
          font-weight: 500;
          box-sizing: border-box;
          text-align: center;
          cursor: pointer;
          border: solid 2px transparent;
          color: rgba(62, 89, 123, 0.3);
          background-color: #f5f5f5;
          padding: 5px;
            &>.includeContent{
              border: 1px solid #DDD;
              height 80px;
              &.include {
                color: #3E597B;
                background-color: #fff;
              }
              &.active {
                border: 2px solid $blue;
                background: #BCDCFF;
                color: $blue;
              }
              &:hover{
                border: 2px solid $blue;
              }
          }
          .day {
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            &>.d_one{
              position: absolute
              top 5px
              left 5px
            }
            &>.d_two{
              position: absolute
              top 5px
              right 5px
            }
            &>.d_three{
              width 100%
              position: absolute
              top 40px
              left 50%;
              transform: translateX(-50%)
            }
          }
          &:nth-child(1),
          &:nth-child(7),
          &:nth-child(8),
          &:nth-child(14),
          &:nth-child(15),
          &:nth-child(21),
          &:nth-child(22),
          &:nth-child(28),
          &:nth-child(29),
          &:nth-child(35),
          &:nth-child(36),
          &:nth-child(42) {
            background: #f6f6f6;  //根据自己需要,设置td周末的背景颜色
          }
        }
        tbody {
          .clickDay {
            border: solid 2px #00BBBB;
          }
        }
      }
    }
    
    </style>
    

    使用注意事项

    1.<style lang="stylus" scoped>这里我用的是stylu
    2.子组件props中的 type 和 height 我在父组件中没有传,使用的是子组件的默认值
    3.data(){} 中 defaultDate、courseList、allDate参数请根据项目实际获取参数使用

    结束 over

    相关文章

      网友评论

          本文标题:vue中日期与日历联动组件(自定义日历组件)

          本文链接:https://www.haomeiwen.com/subject/kqtoyrtx.html