Vue.js(18)之 封装calendar组件

效果

需求

1、实现一个日历组件,如图:

 

2、显示某天的事项:

3、事项是模拟父组件请求接口返回的,数据格式如下:

[
        {
          id: '232',
          date: '2019-06-01',
          info: '我要去吃大餐'
        },
        {
          id: '292',
          date: '2019-06-06',
          info: '我要去吃大餐'
        },
        {
          id: '292',
          date: '2019-06-07',
          info: '我要去吃大餐'
        },
        {
          id: '369',
          date: '2019-06-30',
          info: '我要去吃大餐'
        }
      ]

4、把事项添加到日历组件中,数据格式如下:

代码解析

父组件页面:

<template>
  <div class="test-container">
    <h1>Test页面,测试组件</h1>
    <!-- 日历 -->
    <calendar v-if="calendarVisible" @getDateInfo="getDateInfo" :propsInfoList="propsInfoList" :propsTime="propsTime"></calendar>
  </div>
</template>

<script>
import calendar from '@/components/Calendar/Calendar.vue'
export default {
  name: 'test',
  components: {
    "calendar": calendar
  },
  data() {
    return {
      calendarVisible: true,
      propsTime: '',
      propsInfoList: '',
      middle: [
        {
          id: '232',
          date: '2019-06-01',
          info: '我要去吃大餐'
        },
        {
          id: '292',
          date: '2019-06-06',
          info: '我要去吃大餐'
        },
        {
          id: '292',
          date: '2019-06-07',
          info: '我要去吃大餐'
        },
        {
          id: '369',
          date: '2019-06-30',
          info: '我要去吃大餐'
        }
      ]
    }
  },
  created() {
    this.propsInfoList = JSON.stringify(this.middle)
    this.propsTime = this.getToday()
  },
  mounted() {
    window.alert('测试时间为19年 5、6、7月,完成是在6月')
  },
  methods: {
    // 格式化当前日期 YYYY-MM-DD
    getToday() {
      let nowDate = new Date()
      let yy = nowDate.getFullYear().toString()
      let mm = (nowDate.getMonth() + 1 + '').padStart(2,'0')
      let dd = (nowDate.getDate() + '').padStart(2,'0')
      // let hh = nowDate.getHours().toString().padStart(2,'0')
      // let mt = (nowDate.getMinutes() + '').padStart(2,'0')
      // let ss = (nowDate.getSeconds() + '').padStart(2,'0')
      return `${yy}-${mm}-${dd}` // -${hh}-${mt}-${ss}
    },
    // 组件传值
    getDateInfo(year, month) {
      let _this = this
      _this.propsTime = `${year}-${month}`
      _this.calendarVisible = false
      setTimeout(() => {
        _this.propsInfoList = []
        let middle
        if(month == '05') {
          middle  = [
            {
              id: '232',
              date: '2019-05-10',
              info: '我要去吃小餐'
            }
          ]
        } else if (month == '06') {
          middle = _this.middle
        } else if (month == '07') {
          middle  = [
            {
              id: '232',
              date: '2019-07-10',
              info: '我要去吃小餐'
            }
          ]
        } else {
          middle = ''
        }
        _this.propsInfoList = JSON.stringify(middle)
        _this.calendarVisible = true
      }, 100)
    }
  }
}
</script>

日历子组件:

<template>
  <div class="calendar-container">
    <h1>calendar</h1>
    <div class="show-date" @click="clickData">{{showDate}}</div>
    <div class="now-time">今日:{{exactTime}}</div>
    <div class="calendar">
      <ul class="calendar-header">
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
      </ul>
      <ul class="calendar-body">
        <li class="calendar-row" v-for="(item, index) in JSON.parse(calendarData)" :key="index">
          <span v-for="(subItem, subIndex) in item" :class="[subIndex == 0 || subIndex == 6? 'weekend': 'weekday', subItem.type == '1'? 'exact-time': '', subItem.type == '0'? 'already-time': '', subItem.type == '2'? 'soon-time': '']" @click="showInfo(subItem)" :key="subIndex">
            {{subItem.date}}
          </span>
        </li>
      </ul>
    </div>
    <mt-popup v-model="popupVisible" position="bottom">
      <mt-picker :slots="slots" :showToolbar="true" :visibleItemCount="5" :itemHeight="itemsHeight" ref="picker">
        <img src="@/assets/images/picker_cancel.png" class="picker_cancel" v-on:click="cancelFunc()">
        <img src ="@/assets/images/picker_sure.png" class="picker_sure" v-on:click="sureFunc()">
      </mt-picker>
    </mt-popup>
  </div>
</template>

日历子组件逻辑:

import { MessageBox } from 'mint-ui'
export default {
  name: "calendar",
  props: {
    propsTime: String,
    propsInfoList: String
  },
  data() {
    return {
      time: '',
      infoList: '',
      calendarData: [],
      showDate: '',
      exactTime: '',
      itemsHeight: 95 * window.screen.height / 1334,
      popupVisible: false,
      slots: []
    }
  },
  created() {
    this.infoList = this.propsInfoList
    this.time = this.propsTime.split('-')
    const date = this.getToday()
    this.exactTime = date.slice(0,3).join('-')
    this.getCalendar(...(this.time))
    this.getSlotsArray(...(date.slice(0,2)))
  },
  methods: {
    // 日历组件
    getCalendar(year, month) {
      let _this = this
      const rightNow = _this.exactTime
      _this.showDate = `${year}-${month
      const firstDate = new Date(year, month - 1, 1)
      const firstDay = firstDate.getDay()
      const isLeapYear = year % 100 == 0? year % 400 == 0? 1: 0: year % 4 == 0 ? 1: 0
      const monthArray = [31, 28 + isLeapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
      const weeekLines =Math.ceil((monthArray[month - 1] + firstDay)/7)
      let calendar = []
      for(let i = 0; i < weeekLines; i++) {
        let weeekLinesInfo = []
        for(let j = 0; j < 7; j++) {
          const cellNo = i * 7 + j
          const datePerLine = cellNo - firstDay + 1
          if(datePerLine <= 0 || datePerLine > monthArray[month - 1]) {
            let outOfMonth = {
              "type" : 'null',
              "date" : ''
            }
            weeekLinesInfo[j] = outOfMonth
          } else {
            let day = (datePerLine + '').padStart(2,'0')
            let inOfMonth = {
              "type" : '',
              "date" : day,
              "isDone": '',
              "infor": ''
            }
            const propsDate = `${year}-${month}-${day}`
            if(propsDate == rightNow){
              inOfMonth.type = "1"
            }
            const reservations = JSON.parse(_this.infoList)
            for(let k = 0; k < reservations.length; k++) {
              if(propsDate == reservations[k].date){
                // inOfMonth.type = "1"
                inOfMonth.infor = reservations[k].info
                if(rightNow == reservations[k].date) {
                  inOfMonth.type = "1"
                  inOfMonth.isDone = "doing"
                } else if (rightNow > reservations[k].date) {
                  inOfMonth.type = "0"
                  inOfMonth.isDone = "pass"
                } else if (rightNow < reservations[k].date) {
                  inOfMonth.type = "2"
                  inOfMonth.isDone = "will"
                }
              }
            }
            weeekLinesInfo[j] = inOfMonth
          }
        }
        calendar.push(weeekLinesInfo)
      }
      window.console.log(calendar)
      _this.calendarData = JSON.stringify(calendar)
    },
    // 格式化当前日期 YYYY-MM-DD
    getToday() {
      let nowDate = new Date()
      let yy = nowDate.getFullYear().toString()
      let mm = (nowDate.getMonth() + 1 + '').padStart(2,'0')
      let dd = (nowDate.getDate() + '').padStart(2,'0')
      let hh = nowDate.getHours().toString().padStart(2,'0')
      let mt = (nowDate.getMinutes() + '').padStart(2,'0')
      let ss = (nowDate.getSeconds() + '').padStart(2,'0')
      return [yy, mm, dd, hh, mt, ss]
      // return `${yy}-${mm}-${dd}-${hh}-${mt}-${ss}`
    },
    // 组装 picker 数组
    getSlotsArray(year, month){
      let _this = this
      let yearArray = []
      for(let i = -10 ; i <= 10 ; i ++){
        yearArray.push(year - 1 + i)
      }
      let monthArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
      let slots = [
        {
          values:yearArray,
          className:"slot1",
          defaultIndex: 11
        },
        {
          values:monthArray,
          className:"slot2",
          defaultIndex:month - 1
        }
      ]
      _this.slots = slots
    },
    // 显示日期弹窗
    clickData(){
      this.popupVisible = true
    },
    // 取消按钮
    cancelFunc(){
      this.popupVisible = false;
    },
    // 确认按钮
    sureFunc() {
      let _this = this
      _this.popupVisible = false
      const clickData = _this.$refs.picker.getValues()
      const year = clickData[0] + ''
      const month = (clickData[1] + '').padStart(2,'0')
      const day = _this.time[2]
      _this.getDateInfo(year, month)
      _this.getCalendar(year, month)
    },
    // 调用父组件定义的方法
    getDateInfo(year, month) {
      this.$emit('getDateInfo', year, month)
    },
    // 点击展示某天的事项信息
    showInfo(info) {
      let _this = this
      const infor = info
      if(infor.infor) {
        const [year, month] = _this.showDate.split('-')
        console.log(year, month, info)
        const titleDate = `${year}-${month}-${info.date}`
        const preview = info.infor
        MessageBox({
          title: titleDate,
          message: preview,
          showCancelButton: false,
          closeOnClickModal: true
        })
      }
    }
  }
}

其他:为了减少篇幅,省略样式

github地址

猜你喜欢

转载自www.cnblogs.com/houfee/p/10987447.html