用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
功能
- 不展开时,滑动切换周
- 展开时,滑动切换月
- 默认选择当天
- 切换月份后将月份传递给父组件(也可以是其他数据)
要点
移动端左右滑动
安装插件
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