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地址

原文地址:https://www.cnblogs.com/houfee/p/10987447.html

时间: 2024-08-30 14:19:17

Vue.js(18)之 封装calendar组件的相关文章

基于vue.js的图片预览组件2.0.1

基于vue.js的图片预览组件 Github github 安装 npm install enlargeimg --save-dev import enlargeimg from 'enlargeimg'; 基础用法 <enlargeImg :data="files"></enlargeImg> export default { name: 'hello', data () { return { msg: 'Welcome to Your Vue.js App'

vue.js基础知识篇(6):组件详解

第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 Vue.js的组件注册分为全局注册和局部注册. 全局注册使用Vue.component方法.第一个参数是组件名字,第二个参数是组件的构造函数,要么是function,要么是object. <!DOCTYPE html> <html lang="en"> <hea

Vue.js 系列教程 2:组件,Props,Slots

原文:intro-to-vue-2-components-props-slots 译者:nzbin 这是关于 JavaScript 框架 Vue.js 五个教程的第二部分.在这一部分,我们将学习组件,Props 以及 Slots.这个系列教程并不是一个完整的用户手册,而是通过基础知识让你快速了解 Vuejs 以及它的用途. 系列文章: 渲染, 指令, 事件 组件, Props, Slots (你在这!) Vue-cli Vuex 动画 组件和传递数据 如果你熟悉 React 或者 Angular

Vue.js 实例和内置组件 入门

首先来看看实例的概述: 实例就是在构造器外部操作操作构造器内部的属性和方法. 实例的作用就是给Vue提供与其它js及其框架结合使用的接口. 进入实例阶段: 首先来看 Vue.js 搭配 jQuery 使用: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Early Examples Demo</title&g

原生js拼图,封装,组件化

利用原生js实现拼图游戏,实现封装,变为插件,组件化,传入参数调用, 使用立即执行函数,将变量私有化,不污染全局, 利用canvas展示效果,减少dom操作,不影响HTML结构: 1 var myPingTu = (function(){ 2 function init(row_i,dom){ 3 var myCanvas = dom; 4 var row = row_i || 3,// 行列数 5 arr = [], 6 num = row * row;// 块个数 7 if (!myCanv

vue.js学习笔记(Vuejs——组件——props数据传递)

①组件实例的作用域: 是孤立的,简单的来说,组件和组件之间,即使有同名属性,值也不共享. <div id="app"> <add></add> <del></del> </div> <script> var vm = new Vue({ el: '#app', components: { "add": { template: "<button>btn:{{btn

vue.js注册引用全局消息组件

1 注册 在 src/components 下新建 index.js 文件,复制贴入以下代码: 注册全局组件需要使用 Vue.component,第一个参数 'Message' 是组件名称,第二个参数 Message 是一个对象或者函数,我们这里是一个对象.(vue-cli模板下) import Message from './Message' Vue.component('Message', Message) 2 引用 打开 src/main.js 文件,引入 ./components: im

vue.js开发之开关(switch)组件( 自定义 )

...啥也不说了,难受啊 toggle-switch.vue <template> <label role="checkbox" :class="['switch', { toggled }]"> <input type="checkbox" class="switch-input" @change="toggle"/> <div class="switc

Vue.js——60分钟组件快速入门(上篇)

组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HTML元素,封装可重用的HTML代码,我们可以将组件看作自定义的HTML元素. 本文的Demo和源代码已放到GitHub,如果您觉得本篇内容不错,请点个赞,或在GitHub上加个星星!(所有示例都放在GitHub Pages上了,请访问https://github.com/keepfool/vue-tut