MyCalender.vue
<template>
<div>
<div class="calender_header">
<ul>
<li v-for="(item,index) in weekDays" v-text="item" :key="index"></li>
</ul>
</div>
<!--实现的基本思路:
1.月份切换到周的变化:
高度变化
数据变化
-->
<!--遍历日历数组-->
<div
@touchstart.stop="moveStart"
@touchend.stop="moveEnd"
@touchmove.prevent="move"
class="calender_outer">
<div class="calender_father" ref="calenderFatherRef">
<div v-for="(month,index) in dateList" :key="index" class="calender">
<!--每周数据-->
<ul v-for="(week,weekIndex) in month" :key="weekIndex">
<!--每天数据-->
<li @click.stop="(day.mode=='month'&&!day.isCurrentMonth)?'':togglePreCurrentDay(day)" v-for="(day,dayIndex) in week" :key="dayIndex">
<div :class="{today:isToday(day.year,day.month,day.day),selected:isSelected(day.year,day.month,day.day),isCurrentMonth:day.mode=='month'&&!day.isCurrentMonth}">
{{day.day}}
<div v-show="initTotalSign(day.date)" class="circle"></div>
</div>
</li>
</ul>
</div>
</div>
</div>
<div style="display: flex;align-items: center;justify-content: center;height: 20px;">
<div v-show="mode=='week'" class="down" @click="toggleSwitch()"></div>
<div v-show="mode=='month'" class="up" @click="toggleSwitch()"></div>
</div>
</div>
</template>
<script>
import {get3month,get3week,GET_DATE_YEAR_MONTH_DAY} from './calender_bak'
export default {
name: "MyCalender",
props:{
meetingTotalMap:{
type: Object,
default: function () {
return { }
}
},
},
data(){
return {
weekDays:['日', '一', '二', '三', '四', '五', '六'],//当前显示的周
dateList:[],//日历数据
mode:'week',//week,month
current:{
year:null,//年
month:null,//月
day:null//日
},
touchXY:{
startX:0,//开始X坐标
startY:0,//开始Y坐标
endX:0,//结束X坐标
endY:0,//结束Y坐标
moveX:0,//x方向移动距离
moveY:0,//x方向移动距离
}//触摸发生参数
}
},
methods:{
initTargetDate(year,month,day){
this.current={
year:year,//年
month:month,//月
day:day//日
}
this.initData()
},
/*初始化数据*/
initData(){
const {year,month,day}=this.current;
if(this.mode=='week'){
this.dateList=get3week(year,month-1,day);//注意:month范围[0-11]
}else{
this.dateList=get3month(year,month-1);//注意:month范围[0-11]
}
},
/*切换模式*/
toggleSwitch(){
if(this.mode=='week'){
this.mode='month'
}else{
this.mode='week'
}
},
/*上个月或周*/
togglePreDate(){
let {year,month,day}=this.current;
if(this.mode=='week'){
let obj=this.dateList[0][0][new Date(year,month-1,day).getDay()];
year=obj.year;
month=obj.month;
day=obj.day;
}else{
//上个月
if (month===1) {
//上一年12月
year=year-1;
month=12;
}else{
month=month-1;
}
day=1;
}
this.current={
year:year,//年
month:month,//月
day:day//日
}
this.initData();
},
/*下个月或周*/
toggleNextDate(){
let {year,month,day}=this.current;
if(this.mode=='week'){
let obj=this.dateList[2][0][new Date(year,month-1,day).getDay()];
year=obj.year;
month=obj.month;
day=obj.day;
}else{
//下个月
if (month===12) {
//下一年1月
year=year+1;
month=1;
}else{
month=month+1;
}
day=1;
}
this.current={
year:year,//年
month:month,//月
day:day//日
}
this.initData();
},
/*点击选中天*/
togglePreCurrentDay(dayObj){
const {year,month,day}=dayObj;
this.current={ year:year,month:month,day:day }
},
/*事件触发*/
moveStart(e){
let touch;
if(e.changedTouches){
touch = e.changedTouches[0];
}else{
touch = e
}
this.touchXY.startX=touch.clientX;//开始触摸点X
this.touchXY.startY=touch.clientY;//开始触摸点Y
},
move(e){
let touch;
if(e.changedTouches){
touch = e.changedTouches[0];
}else{
touch = e
}
this.touchXY.endX=touch.clientX;//结束触摸点X
this.touchXY.endY=touch.clientY;//结束触摸点Y
this.touchXY.moveX=this.touchXY.endX-this.touchXY.startX//移动距离
this.touchXY.moveY=this.touchXY.endY-this.touchXY.startY//移动距离
if(Math.abs(this.touchXY.moveX)>Math.abs(this.touchXY.moveY)){
let f=this.$refs['calenderFatherRef'];
f.style.transform="translateX("+this.touchXY.moveX+"px)";
}
},
moveEnd(e){
let _this=this;
const {startX,startY,endX,endY,moveX,moveY} =this.touchXY
if(Math.abs(moveX)>10||Math.abs(moveY)>10){
if(Math.abs(moveX)>Math.abs(moveY)){
//X方向切换
if(moveX>0){
_this.togglePreDate()
}else{
_this.toggleNextDate()
}
}else{
//Y方向切换
if(moveY>0&&_this.mode=='week'){
_this.toggleSwitch();
}else if(moveY<0&&_this.mode=='month'){
_this.toggleSwitch();
}
}
}
let f=this.$refs['calenderFatherRef'];
f.style.transform="translateX("+0+"px)";
this.touchXY=Object.assign({},this.$options.data.touchXY)
},
},
created() {
const [year,month,day]=GET_DATE_YEAR_MONTH_DAY();
this.current={
year:year,//年
month:month,//月
day:day//日
}
this.initData()
},
computed:{
/*是否当前选中*/
isSelected(){
const {year,month,day}=this.current;
return (year1,month1,day1)=>{
return year1==year&&month1==month&&day1==day;
}
},
/*是否今天*/
isToday(){
const [year1,month1,day1]=this.$GET_DATE_YEAR_MONTH_DAY();
return (year,month,day)=>{
return year1==year&&month1==month&&day1==day;
}
},
/*初始化标记*/
initTotalSign(){
let map=this.meetingTotalMap;
return (date)=>{
if(map[date]&&map[date]>0){
return true;
}else{
return false;
}
}
},
/*该行是否全是下个月的*/
/*isOtherMonth(){
let mode=this.mode;
return (week)=>{
if(mode=='month'){
for(let day of week){
if(day.isCurrentMonth){
return true;
}
}
return false;
}
return true;
}
}*/
},
watch:{
/*监听:模式切换*/
mode(val,oldVal) {
this.initData()
},
/*监听选中改变*/
current:{
deep:true,
handler:function (val,oldVal) {
const {year,month,day}=val;
const {year:yearOld,month:monthOld,day:dayOld}=oldVal;
if((year+'-'+month)!=(yearOld+'-'+monthOld)){
this.$emit('yearMonthChange',year,month);//年月改变
}
this.$emit('dateChange',year,month,day);//选中日期改变
}
}
}
}
</script>
<style scoped>
/* 日历 */
.calender_header ul {display: flex;box-shadow: -1px 0 2px #333333;}
.calender_header li {flex: 1;height: 30px;text-align: center;line-height: 30px;font-size: 8px;}
.calender_outer{position: relative;width: 100%;overflow: hidden;box-shadow: 1px 0 2px #333333;}
.calender_father{position: relative;width: 300%;display: flex;left: -100%;}
.calender {position: relative;width: 100%;}
.calender ul {display: flex;}
.calender li {flex:1;position: relative;height:50px;display: flex;align-items: center;justify-content: center;}
.circle { width: 4px; height: 4px; border-radius: 50%; background-color: #2183FE; position: absolute; bottom: 6px; left: 44%;}
.today{color:#2183FE;}
.selected{ width:40px;height:40px;line-height:40px;border-radius: 50%;background: #2183FE;color: white;text-align: center;position: relative;}
.selected .circle{background-color: #FFFFFF;}
.isCurrentMonth {color:#f2f2f2!important;}
/*css实现上下左右箭头*/
.down{
border-right: 2px solid #343c99;
border-top: 2px solid #343c99;
height: 10px;
width: 10px;
transform: rotate(135deg);
}
.up{
border-left: 2px solid #343c99;
border-bottom: 2px solid #343c99;
height: 10px;
width: 10px;
transform: rotate(135deg);
margin-top: 11px;
}
</style>
calender_bak.js
/*注意:month范围[0-11]*/
function format(year, month, day) {
month++;
month < 10 && (month = "0" + month);
day < 10 && (day = "0" + day);
return year + "-" + month + "-" + day;
}
/*注意:month范围[0-11]*/
export function getMonth(year, month) {
let monthArr = [];//月份日期数组
let dtFirst = new Date(year, month, 1); //每个月第一天
let dtLast = new Date(year, month + 1, 0); //每个月最后一天
let monthLength = dtLast.getDate() - dtFirst.getDate() + 1;
let space = (dtFirst.getDay()+ 7) % 7; //月历前面空格
for (let i = -space; i < 36; i += 7) {
let week = [];//每一周的数据(一行)
for (let j = 0; j < 7; j++) {
let day = i + j + 1;//日
if (day > 0 && day <= monthLength) {
week.push({
mode: "month",
day: day,
year: year,
month: month+1,
date: format(year, month, day),
isCurrentMonth:true,
});
} else {
//其它月份
let newdt = new Date(year, month, day);
let years = newdt.getFullYear();
let months = newdt.getMonth();
let days = newdt.getDate();
week.push({
mode: "month",
day: days,
year: years,
month: months+1,
date: format(years, months, days),
isCurrentMonth:false,
});
}
}
monthArr.push(week);
}
return monthArr;
}
/*注意:month范围[0-11]*/
export function getWeek(year, month, day) {
let dt = new Date(year, month, day);
let weekArr = [];
let dtFirst = new Date(year, month, day - ((dt.getDay() + 6) % 7));//周一
let week = [];
//循环选中当天所在那一周的每一天
for (let j = -1; j < 6; j++) {
let newdt = new Date(
dtFirst.getFullYear(),
dtFirst.getMonth(),
dtFirst.getDate() + j
);
let years = newdt.getFullYear();
let months = newdt.getMonth();
let days = newdt.getDate();
week.push({
mode: "week",
day: days,
year: years,
month: months+1,
date: format(years, months, days),
});
}
weekArr.push(week);
return weekArr;
}
/** 获取三月:上月、这月、下月;注意:month范围[0-11]*/
export function get3month(year, month){
let monthList = [];
if (month===0) {
monthList.push(getMonth(year-1, 11));//上一年的十二月
} else {
monthList.push(getMonth(year, month - 1));
}
monthList.push(getMonth(year, month));
if (month===11) {
monthList.push(getMonth(year+1, 0));//获取下一年的1月的
} else {
monthList.push(getMonth(year, month + 1));
}
return monthList;
}
/** 获取三周:上周、这周、下周;注意:month范围[0-11]*/
export function get3week(year,month,day) {
let monthList = [];
monthList.push(getWeek(year, month, day - 7));
monthList.push(getWeek(year, month, day));
monthList.push(getWeek(year, month, day + 7));
return monthList;
}
export function GET_DATE_YEAR_MONTH_DAY (){
let d=new Date();
let year=d.getFullYear();
let month=d.getMonth() + 1;
let day=d.getDate();
return [year,month,day];
}
使用效果Test.vue
<template>
<div class="container">
<div style="padding: 10px 12px;text-align: center;">{{dateStr}}</div>
<my-calender ref="calenderRef" :meetingTotalMap="meetingTotalMap" @yearMonthChange="yearMonthChange" @dateChange="dateChange"></my-calender>
<!--会议列表-->
<div>
<div style="flex: 1;overflow: auto;background: #FAFAFA;">
<div v-for="(item,index) in 100" :key="index" style="padding: 10px 12px;background-color: #FFE7E7;margin: 10px;">{{item}}</div>
</div>
</div>
</div>
</template>
<script>
import MyCalender from '../../components/calender/MyCalender'
export default {
name: "Test",
components:{
MyCalender:MyCalender
},
data(){
return {
dateStr:'',//当前时间
meetingTotalMap:{
'2021-08-20':1
},//标记
}
},
methods:{
//时间月份改变
yearMonthChange(year,month){
const strDate=year+"-"+(month<10?("0"+month):month)+"-01";
},
//选中日期改变
dateChange(year,month,day){
this.dateStr=year+"-"+(month<10?("0"+month):month)+"-"+(day<10?("0"+day):day);
}
}
}
</script>
<style scoped>
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.container > div:last-child {
flex: 1;
min-height: 0;
position: relative;
display: flex;
flex-direction: column;
}
</style>