openks / learn-vue

自定义组件文档
https://openks.github.io/learn-vue
0 stars 0 forks source link

20180205_定制日历功能的实现 #77

Open openks opened 6 years ago

openks commented 6 years ago

定制日历这种功能做过N次了,每次都是在需要的时候重新写,这次记录下,便于以后用到时查找

需求:
用日历格式显示前7天或者前30天的每一天是否有数据传输,
如果有则用一种颜色表示 状态A
如果无则用另一种颜色显示 状态B
今日之后的日历灰掉 状态C
统计数据之前的日期正常显示 状态D

从需求的角度讲可以也可以简化为2种状态,一种是有数据状态A,一种是其他状态B

实现方案:
本来想的是根据当前日期判断前7天或前30天是否跨月
如果跨月显示两个月的日历
如果不跨月只显示一个月的日历即可
再根据数据判断如果有记录则显示状态,其他不做处理,
但是根据需求明显不止两种状态
虽说状态增多但主要逻辑依然正确,只不过要显示的状态多了点

关于跨月简单举例,
如今天是2018年1月5号则前7天和前30天均跨月
如今天是2018年1月31号则前7天和前30天均不跨月
如今天是2018年1月9号则前7天不跨月但前30天跨月
有且只有这3种情况

组件源代码如下:

<!--  cleader.vue  -->
<template lang="html">
    <div class="calanderWp" :class="{'hide':!dialogVisible}">
        <div class="calander prev"
             v-if="JSON.stringify(dayPreInfo).length!==2">
            <div class="cal-title">{{dayPreInfo.date}}</div>
            <ul class="cal-ul">
                <li class="cal-li"
                    v-for="it in ['日','一','二','三','四','五','六',]">{{it}}</li>
                <li class="cal-li"
                    v-for="emp in dayPreInfo.weekone"></li>
                <li class="cal-li"
                    :class="[showData(getDate(dayPreInfo.year,dayPreInfo.month,em))]"
                    :date="getDate(dayPreInfo.year,dayPreInfo.month,em)"
                    v-for="em in dayPreInfo.days">{{em}}</li>
            </ul>
            <div class="status">
              <span class="item2"><span class="tran"></span><span>已传输</span></span>
              <span class="item1"><span class="untran"></span><span>未传输</span></span>
            </div>
        </div>
        <div class="calander">
            <div class="cal-title">{{dayInfo.date}}</div>
            <ul class="cal-ul">
                <li class="cal-li"
                    v-for="it in ['日','一','二','三','四','五','六',]">{{it}}</li>
                <li class="cal-li"
                    v-for="emp in dayInfo.weekone"></li>
                <li class="cal-li"
                    :class="[showData(getDate(dayInfo.year,dayInfo.month,em))]"
                    :date="getDate(dayInfo.year,dayInfo.month,em)"
                    v-for="em in dayInfo.days">{{em}}</li>
            </ul>
            <div class="status">
              <span class="item2"><span class="tran"></span><span>已传输</span></span>
              <span class="item1"><span class="untran"></span><span>未传输</span></span>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    props: {
        visible: {
            type: Boolean,
            default: true
        },
        period: {
            type: Number,
            default: 7
        },
        dataList: {
            type: Array,
            default: function () {
                return []
            }
        }
    },
    data () {
        return {
            dataFromDate: '', // 数据开始时间
            dayPreInfo: {}, // 上个月数据
            dayInfo: {} // 本月信息 用于绘制日历
        }
    },
    computed: {
        dialogVisible: {
            set (newValue) {
                this.$emit('update:visible', newValue)
            },
            get () {
                return this.visible
            }
        }
    },
    methods: {
        getPrevData (date) {
            return this.moment(this.dataFromDate).diff(this.moment(date)) > 0
        },
        showData (date) {
            let t = [
                {
                    'date': '2018-01-20'
                }, {
                    'date': '2018-01-27'
                }, {
                    'date': '2018-01-29'
                }, {
                    'date': '2018-01-30'
                }, {
                    'date': '2018-01-31'
                }, {
                    'date': '2018-02-01'
                }]
            if (this.dataList.length > 0) {
                t = this.dataList
            }
            let tmp = t.map(ele => {
                return ele.date
            })
            let ret = ''
            let dfdm = this.moment(this.dataFromDate)
            let dm = this.moment(date)
            let tdm = this.moment()
            console.log('this.dataFromDate', this.dataFromDate)
            console.log('date', date)
            if (dfdm.diff(dm) > 0) {
                ret = 'prev'
            } else if (tmp.includes(date)) {
                ret = 'date'
            } else if (dm.diff(tdm) > 0) {
                ret = 'next'
            } else {
                ret = 'no-date'
            }
            return ret
        },
        getDate (year, month, day) {
            return year + '-' + month + '-' + (day < 10 ? '0' + day : day)
        },
        dealTimes () {
            // console.log('ref', this.$refs.inpa.value)
            let t = this.period
            let dinfo = this.dayInfo
            this.dataFromDate = this.moment().subtract((parseInt(t, 10) + 1), 'd')
            if (dinfo.day < t) {
                let d = new Date(dinfo.year, dinfo.month - 2, 1)
                this.dayPreInfo = this.getDayInfo(d)
                // console.log('获取2个月数据', this.dayPreInfo, d)
            } else {
                this.dayPreInfo = {}
                // console.log('获取1个月数据')
            }
        },
        /**
         * 获取该日是周几 0-6,该月共几天,该日是几号
         * @method   getDayInfo
         * @param    {[Date]}                date [description]
         * @return   {Object}                     [description]
         * @datetime 2018-02-02T14:31:10+080
         */
        getDayInfo: function (date) {
            var inDate = date || new Date()
            var tmp = {}
            // 0-6分别表示周日到周六
            tmp.week = inDate.getDay()
            // 该日所在月天数
            tmp.days = this.getDays(inDate.getFullYear(), inDate.getMonth())
            // 该日日期
            tmp.day = inDate.getDate()
            // 该月1号是周几
            tmp.weekone = new Date(inDate.getFullYear(), inDate.getMonth(),
                    1)
                .getDay()
            tmp.date = this.moment(inDate)
                .format('YYYY-MM')
            tmp.year = inDate.getFullYear()
            let m = inDate.getMonth() + 1
            tmp.month = m < 10 ? '0' + m : m
            return tmp
        },
        /**
         * 根据年份及月份获取该月天数
         * @param  {[Number]} yeara  4位年份
         * @param  {[Number]} montha 当前月份减一值
         * @return {Number}          当前月份总天数
         */
        getDays: function (yeara, montha) {
            // console.log("year-month:", yeara, montha);
            var td = new Date()
            var month = montha
            var days = 0
            var big = [1, 3, 5, 7, 8, 10, 12]
            var year = yeara || td.getFullYear()
            //  montha 可能为0 所以不能用或运算符
            if (typeof (month) === 'undefined') {
                month = td.getMonth()
            }
            month = month + 1
            // console.log("year-month2:", year, month);
            if (month === 2) {
                if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
                    days = 29
                } else {
                    days = 28
                }
            } else {
                if (big.indexOf(month) > -1) {
                    days = 31
                } else {
                    days = 30
                }
            }
            // console.log("year-month3:", days);
            return days
        }
    },
    mounted () {
        this.dayInfo = this.getDayInfo()
        this.dealTimes()
    }
}
</script>

<style lang="less">
.calanderWp {
    &.hide {
      display: none
    }
    .calander {
        width: 224px;
        padding: 20px 20px 10px;
        background: #fff;
        float: left;
        &.prev {
            border-right: 1px solid #e3e3e3;
        }
        .cal-title {
            text-align: center;
            height: 30px;
            font-size: 14px;
        }
        .cal-ul {
            overflow: hidden;
            margin: 0;
            padding: 0;
            background: #fff;
            .cal-li {
                float: left;
                display: block;
                width: 30px;
                height: 30px;
                line-height: 30px;
                text-align: center;
                margin: 1px;
                &.today{
                    background-color: #eeeeee;
                }
                &.prev {
                    background-color: #FFF;
                }
                &.no-date {
                    background-color: #D3DCE6;
                }
                &.date {
                    background-color: #FBBD00;
                }
                &.next {
                    color: #C0CCDA;
                }
            }
        }
        .status {
            display: flex;
            justify-content: center;
            padding: 8px 0 0;
            .untran,.tran{
                display: flex;
                width: 16px;
                height: 12px;
                margin-right: 5px;
                background-color: #D3DCE6;
            }
            .item1,.item2{
                display: flex;
                 align-items: center;
            }
            .item2{
                margin-right: 10px;
            }
            .tran{
                background-color: #F6CE00;
            }
        }
    }
}
</style>

使用方法

<div class="wpper">
    <el-button type="primary"
        size="small"
        class="m-x-r"
        @click="testBtnClick('showDialog6')">测试数据功能</el-button>
    <test-info :visible.sync="showDialog6" :period="30" class="test1"></test-info>
</div>
<script>
import testInfo from '../cleader.vue'
export default {
    components: {
        'test-info': testInfo
    },
    data () {
        return {
            showDialog6: false
        }
    },
    methods: {
        testBtnClick (item) {
            this[item] = !this[item]
        }
    }
}
</script>