其他分享
首页 > 其他分享> > 用vuejs仿写一个移动端日历组件

用vuejs仿写一个移动端日历组件

作者:互联网

仿写一个日历组件,有些粗糙,需要优化的地方欢迎提出!

参考文章:

https://www.jianshu.com/p/67acaaf7d2f7

https://blog.csdn.net/zxb89757/article/details/103579415?ops_request_misc=%7B%22request%5Fid%22%3A%22160359079019195264707225%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=160359079019195264707225&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v28-13-103579415.pc_first_rank_v2_rank_v28&utm_term=%E5%B0%81%E8%A3%85%E6%97%A5%E5%8E%86%E7%BB%84%E4%BB%B6&spm=1018.2118.3001.4187

https://www.jianshu.com/p/612cd47b966d

功能

导出_122526_2.gif

要点

移动端左右滑动

安装插件

npm install vue-touch@next --save

在main.js 中 引入:

import VueTouch from 'vue-touch'
Vue.use(VueTouch, {name: 'v-touch'})
VueTouch.config.swipe = {
    threshold: 100 //手指左右滑动距离
}

使用

<v-touch @swipeleft="onSwipeLeft" @swiperight="onSwipeRight"  tag="div">
	(你的组件)
</v-touch>

获取每月的天数

首先列出每月的天数(2月除外)

monthDay:[31,'',31,30,31,30,31,31,30,31,30,31],

接着判断2月是否为闰月再将天数插入该数组

this.February=this.isLeapYear(this.year)?29:28//获取二月份的天数
this.monthDay.splice(1,1,this.February) //插入二月份的天数
isLeapYear(year){
	return year%4==0&&year%100!==0||year%400==0
},

最后传入月份的索引,循环每个月的天数

<p v-for="(item,idx) in (monthDay[this.month-1] || 30)" 
    :key="item.id">
    {{item}}
</p>

补充前后空格

<p v-for="item in headDays" :key="item.id" class="grey">{{item}}</p>
//中间是当月有效天
<p v-for="item in tailDays" :key="item.id" class="grey">{{item}}</p>
getWholeMonth(){
	//获取某年某月的第一天,由于new Date的月份按索引判断,所以-1
	let firstDay = new Date(this.year,this.month-1,1) 
    //获取前方空格数
    if(firstDay.getDay() == 0){
        this.spaceDay = 6
    } else {
        this.spaceDay = firstDay.getDay() - 1
    }
    this.getPrevDays() //补前方空格
    this.getCells()    //补后方空格
},
//补前方空格
getPrevDays(){
	//this.month表示的是月份,
    //如果当前月为一月份,获取十二月份的天数并传过去。所以传索引11
    if(this.month==1){
        this.getHeadDays(this.monthDay[11])
    }else{
        this.getHeadDays(this.monthDay[this.month-2])
    }
},
//补后方空格-中间函数-获取方格数
getCells(){
	let cells=this.spaceDay+this.monthDay[this.month-1]
    //余数不能为0(否则就补一行了),cells%7获取余数
    //一周有7天,假设余数为2,那么后方没有补的空格就位7-2
    if(7-cells%7!==0){
   		this.getTailDays(7-cells%7)
    }
},
//补后方空格
getTailDays(end){
	this.tailDays=this.supDays.slice(0,end)
},

其中:

leftDays:[31,30,29,28,27,26,25,24,23,22], //用于截取的数组 补前方空格
supDays:[1,2,3,4,5,6,7],                  //用于截取的数组 补后方空格

切换月与周

切换月,实质上就是改变变量month,让其动态获取monthDay中的天数

切换周,实质上就是移动日历的上下位置,当展开时,位置在第一行;当未展开时,动态改变位置,其中weekRow是变量:

<div class="relative" :class="[visible?'row-1':'row-'+weekRow]">(被包裹的日历)</div>
.row-1{
    top:0
}
.row-2{
    top:-2.4em
}
.row-3{
    top:-4.8em
}
.row-4{
    top:-7.2em
}
.row-5{
    top:-9.6em
}
.row-6{
    top:-12em
}

以向左滑为例

onSwipeLeft(){
    //1.展开的情况下 滑动切换月份
    if(this.visible){
        if(this.month==12){
            this.year++
            this.month=1
        }else{
            this.month++
        }
        this.getWholeMonth()
    }else{
    //2.未展开的情况下 滑动切换周
        this.getWholeMonth()//先获取当前行
        //当前周小于行数时,切换下一周
        if(this.weekRow<this.rows){
            this.weekRow++
        }else{
        //当前周等于行数时,切换下一个月份,当前周变成第一周。
        //由于要切到第一周,所以不用获取下个月的行
            if(this.month==12){
                this.year++
                this.month=1
                this.weekRow=1
            }else{
                this.month++
                this.weekRow=1
            }
            this.getWholeMonth()//由于更换了月,所以调用该函数补空格
        }
    }   
        
},

父组件监听子组件数据变化

子组件

updated(){
    this.$emit('monthChange', this.month);
},

父组件

<Calendar ref="calendar"  @monthChange="updateMonth"/>
current:1//月份

mounted(){
	this.current=this.$refs.calendar.month
},
methods:{
    updateMonth(month){
    	this.current=month
    },
},

完整源码

子组件

<template>
  <div>
    <div class="calendar" :class="[!visible?'hidden':'']" >
        <div class="flex_sb cellbox">
            <p v-for="item in weekList" :key="item.id" class="week">{{item}}</p>
        </div>

        <v-touch @swipeleft="onSwipeLeft" @swiperight="onSwipeRight" tag="div">
            <div class="flex_sb cellbox border relative"  :class="[visible?'row-1':'row-'+weekRow]">
                <p v-for="item in headDays" :key="item.id" class="grey">{{item}}</p>
                <p v-for="(item,idx) in (monthDay[this.month-1] || 30)" 
                    @click="setDay(idx)" 
                    :class="idx==activeDay?'active':''"
                    class="relative"
                    :key="item.id">
                    {{item}}
                </p>
                <p v-for="item in tailDays" :key="item.id" class="grey">{{item}}</p>
            </div>
        </v-touch>
    </div>
    <div>
        <van-icon name="arrow-down" v-if="!visible" @click="visible=true"/>
        <van-icon name="arrow-up" @click="visible=false" v-else/>
    </div>
  </div>
</template>

<script>
export default {
    data(){
        return{
            year:'',        //年
            month:'',       //月
            day:'',         //日
            weekList:['一','二','三','四','五','六','日'],
            monthDay:[31,'',31,30,31,30,31,31,30,31,30,31],
            February:'',    //判断2月份的天数
            
            spaceDay: '',   //当月日期前方的空格数
            leftDays:[31,30,29,28,27,26,25,24,23,22], //用于截取的数组 补前方空格
            supDays:[1,2,3,4,5,6,7],                  //用于截取的数组 补后方空格
            headDays:[],    //上个月月尾日期
            tailDays:[],    //下个月月头日期

            activeDay: '',  //选中的日期 索引
            visible:false,  //判断日历是否展开
            weekRow:2,     //当前周 用于按周切换
            rows:''        //当前月的周数
        }
    },
    created(){
        this.getTheCurrentDate() //获取当前日期(年月日)
        this.February=this.isLeapYear(this.year)?29:28//获取二月份的天数
        this.monthDay.splice(1,1,this.February) //插入二月份的天数
        this.getWholeMonth() //获取完整月份日历
        this.defaultSet()
    },
    updated(){
        //监听滑动事件后月份的变化,将月份传给父组件
        this.$emit('monthChange', this.month);
    },
    methods:{
        //判断是否为闰年
        isLeapYear(year){
            return year%4==0&&year%100!==0||year%400==0
        },

        //获取当前日期
        getTheCurrentDate(){
            let current=new Date()
            this.year = current.getFullYear()
            this.month = current.getMonth() + 1
            this.day = current.getDate()
        },

        //默认选择当前日期
        defaultSet(){
            //展示周时,获取当日的行数
            if(!this.visible){
               this.weekRow=Math.ceil((this.spaceDay+this.day)/7)
            }
            this.setDay(this.day-1)
        },

        //获取空格被填充过的完整的月
        getWholeMonth(){
            let firstDay = new Date(this.year,this.month-1,1) //获取某年某月的第一天,由于new Date的月份按索引判断,所以-1
            //获取前方空格数
            if(firstDay.getDay() == 0){
                this.spaceDay = 6
            } else {
                this.spaceDay = firstDay.getDay() - 1
            }
            this.getPrevDays() //补前方空格
            this.getCells()    //补后方空格
        },
        
        //获取上个月的天数 并调用函数补充开头空格
        getPrevDays(){
            //this.month表示的是月份,
            //如果当前月为一月份,获取十二月份的天数并传过去。所以传索引11
            if(this.month==1){
                this.getHeadDays(this.monthDay[11])
            }else{
                this.getHeadDays(this.monthDay[this.month-2])
            }
        },
        //补开头空格
        getHeadDays(end){
            if(end==31){
                this.headDays=this.leftDays.slice(0,this.spaceDay).reverse()
            }else if(end==30){
                this.headDays=this.leftDays.slice(1,this.spaceDay+1).reverse()
            }else if(end==29){
                this.headDays=this.leftDays.slice(2,this.spaceDay+2).reverse()
            }else if(end==28){
                this.headDays=this.leftDays.slice(3,this.spaceDay+3).reverse()
            }
        },
        //获取月份方格数,用于补后方空格 并获取行/重新获取行
        getCells(){
            let cells=this.spaceDay+this.monthDay[this.month-1]
            //余数不能为0(否则就补一行了),cells%7获取余数
            //一周有7天,假设余数为2,那么后方没有补的空格就位7-2
            if(7-cells%7!==0){
                this.getTailDays(7-cells%7)
            }
            //向上取整
            this.rows=Math.ceil(cells/7)
        },
        //补后方空格
        getTailDays(end){
            this.tailDays=this.supDays.slice(0,end)
        },

        //选取特定日期
        setDay(idx){
            this.activeDay = idx
            this.day = idx + 1
            console.log('选择的日期是'+this.year+' '+this.month+' '+this.day)
        },

        //右滑 下一个
        onSwipeLeft(){
            //1.展开的情况下 滑动切换月份
            if(this.visible){
                if(this.month==12){
                    this.year++
                    this.month=1
                }else{
                    this.month++
                }
                this.activeDay = 0
                this.getWholeMonth()
            }else{
            //2.未展开的情况下 滑动切换周
                this.getWholeMonth()//先获取当前行
                //当前周小于行数时,切换下一周
                if(this.weekRow<this.rows){
                    this.weekRow++
                }else{
                //当前周等于行数时,切换下一个月份,当前周变成第一周。
                //由于要切到第一周,所以不用获取下个月的行
                    if(this.month==12){
                        this.year++
                        this.month=1
                        this.weekRow=1
                    }else{
                        this.month++
                        this.weekRow=1
                    }
                    this.getWholeMonth()//由于更换了月,所以调用该函数补空格
                }
            }   
                
        },
        //左滑 上一个
        onSwipeRight(){
            //1.展开的情况下 滑动切换月份
            if(this.visible){
                if(this.month==1){
                    this.year--
                    this.month=12
                }else{
                    this.month--
                }
                this.activeDay = 0
                this.getWholeMonth()
            }else{
            //2.未展开的情况下 滑动切换周
                //当前周大于1时,切换上一周
                if(this.weekRow>1){
                    this.weekRow--
                }else{
                //当前周等于1时,切换上一个月,并把当前周变成上个月的最后一周
                    if(this.month==1){
                        this.year--
                        //成功切换到上个月
                        this.month=12
                        //调用该函数重新获取行数
                        this.getWholeMonth()
                        this.weekRow=this.rows
                    }else{
                        this.month--
                        this.getWholeMonth()
                        this.weekRow=this.rows
                    }  
                }
            }
            
        },
    }
}
</script>

<style lang="scss" scoped>
.calendar{
    font-size: .8em;
    width: 80%;
    margin: 0 auto;
    height: auto;
    .flex_sb{
        display: flex;
        justify-content:space-between;
    }
    .grey{
        background-color: rgb(247, 244, 244);
    }
    .relative{
        position: relative;
    }
    &.hidden{
        height: 4.8em;
        overflow: hidden;
    }

    .week{
        z-index: 10;
        background: #fff;
    }
    .cellbox{
        flex-wrap: wrap;
        margin: 0;
        p{
            display: inline-block;
            width:14.28%;
            height:2.4em;
            line-height: 2.4em;
            box-sizing: border-box;
            margin: 0;
            &.active{
                color: #eee;
                background-color: #409EFF;
            }
        }
    }
    .border{
        p{
            border: 1px solid #eee;
        }
    }
    .row-1{
        top:0
    }
    .row-2{
        top:-2.4em
    }
    .row-3{
        top:-4.8em
    }
    .row-4{
        top:-7.2em
    }
    .row-5{
        top:-9.6em
    }
    .row-6{
        top:-12em
    }

}


</style>

父组件:

<van-cell :title="monthTitle" />
<Calendar ref="calendar"  @monthChange="updateMonth"/>

<script>
import Calendar from './../../components/calendar'
	export default{
		components:{
			Calendar
		},
		data(){
			return{
				current:8
			}
		},
		mounted(){
			this.current=this.$refs.calendar.month
		},
		methods:{
			//只要子组件数据变化了,就调用该函数
			updateMonth(month){
				this.current=month
			},
		},

		computed:{
			monthTitle(){
				return "出勤月报"+"("+this.month.current+"月)"
			}
		}
	}
</script>

标签:仿写,vuejs,31,日历,month,空格,获取,else,row
来源: https://www.cnblogs.com/sanhuamao/p/13878015.html