| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- <template>
- <div class="calendar">
- <div class="c__hd">
- <div class="c__date" @click="onToggleType">{{ curDays.year }}年<span>{{ curDays.month.toString().length >= 2 ? curDays.month : '0' + curDays.month }}月</span></div>
- <div class="c__change" v-if="calendarType !== 'small'">
- <!-- <van-icon name="arrow-left" />
- <van-icon name="arrow" /> -->
- <img :src="imgs.arrow1" alt="" @touchstart.stop.prevent="slidePrev" @touchend.stop.prevent="endTouch" class="arrow arrow-left">
- <img :src="imgs.arrow2" alt="" @touchstart.stop.prevent="slideNext" @touchend.stop.prevent="endTouch" class="arrow">
- </div>
- </div>
- <div class="week-title">
- <span>一</span>
- <span>二</span>
- <span>三</span>
- <span>四</span>
- <span>五</span>
- <span>六</span>
- <span>日</span>
- </div>
- <swiper :options="swiperOption" ref="mySwiper" @slideChangeTransitionEnd="slideChangeTransitionEnd" style="height: auto">
- <swiper-slide v-for="(day, current) in daySet" :key="current">
- <div class="tr">
- <template v-for="(i, index) in day">
- <div :key="index" :class="[calendarType == 'small' ? 'small' : '', 'td']">
- <span @click.stop="onSelectDay(i)"
- :class="[i.disabled ? 'disabled' : '',
- i.noCheck? 'noCheck' : '',
- i.toDay ? 'today' : '',
- i.nowDate == selectElement ? 'active' : '']">{{ i.dayNum }}</span>
- </div>
- </template>
- </div>
- </swiper-slide>
- </swiper>
- </div>
- </template>
- <script>
- import 'swiper/dist/css/swiper.css'
- import { swiper, swiperSlide } from 'vue-awesome-swiper'
- import dayjs from 'dayjs'
- export default {
- name: 'calendar',
- components: { swiper, swiperSlide },
- props: {
- dataList: {
- type: Array,
- default() {
- return []
- }
- },
- dayList: { // 当月哪天有数据
- type: Array,
- default() {
- return []
- }
- },
- type: {
- type: String,
- default: 'default' // small 一排日历
- }
- },
- data() {
- return {
- calendarType: this.type, // 日历类型
- dayDateList: [],
- swiperOption: {
- autoHeight: true,
- initialSlide: 13,
- // loop:false,
- // mode: 'horizontal',
- // freeMode:false,
- // touchRatio:0.5,
- // longSwipesRatio:0.1,
- // threshold:50,
- // followFinger:false,
- centeredSlides: true,
- observer: true,//修改swiper自己或子元素时,自动初始化swiper
- observeParents: true,//修改swiper的父元素时,自动初始化swiper
- // effect : 'coverflow',
- },
- OS: Object.prototype.toString,
- // 一周的第一天
- // 0表示周日,依次类推
- startWeek: 1,
- daySet: [], // 月数据
- curDays: {
- year: new Date().getFullYear(),
- month: new Date().getMonth() + 1
- },
- points: { // 手势移动位置
- startX: 0,
- startY: 0,
- endX: 0,
- endY: 0
- },
- selectElement: null, // 选中的元素 根据日期来判断是否一致
- imgs:{
- arrow1:require('@/assets/images/arrow.png'),
- arrow2: require('@/assets/images/arrow.png')
- }
- }
- },
- methods: {
- isLeap(y) { // 是否是润年
- return (y % 100 !== 0 && y % 4 === 0) || (y % 400 === 0);
- },
- isDate(obj) { // 是否是日期格式
- return this.OS.call(obj === '[object Date]')
- },
- dateToString(date) {
- if(!this.isDate(date)) {
- return false
- }
- return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()
- },
- getSiblingsMonth(y, m, n) { // 获取弟兄年月
- var d = new Date(y, m - 1)
- d.setMonth(m - 1 + n)
- return {
- y: d.getFullYear(),
- m: d.getMonth() + 1
- }
- },
- getDaysNum(y, m) { // 获取m月有几天
- let num = 31;
- switch (m) {
- case 2:
- num = this.isLeap(y) ? 29 : 28;
- break;
- case 4:
- case 6:
- case 9:
- case 11:
- num = 30;
- break;
- }
- return num;
- },
- getPrevMonth(y, m, n) {
- return this.getSiblingsMonth(y, m, 0 - (n || 1))
- },
- getNextMonth(y, m, n) {
- return this.getSiblingsMonth(y, m, n || 1)
- },
- getListMonth() { // 获取14个月的数据
- this.daySet = [] //
- // 生成前12个月的数据
- for(let i = 12; i >= -2; i--) {
- this.daySet.push(this.getDaysSet(new Date(this.curDays.year, this.curDays.month - (i + 2))))
- }
- },
- getDayItem(y, m, d, f) { // 填充数据
- let toDay = false // 是否是当天
- let cD = new Date()
- if(cD.getFullYear() === y && cD.getMonth() + 1 === m && cD.getDate() === d && f === 2) {
- toDay = true
- this.selectElement = new Date(y, m - 1, d)
- }
- let tDisabled
- if(this.calendarType == 'small') {
- tDisabled = 0
- } else {
- if(f === 2) {
- tDisabled = 0
- } else {
- tDisabled = 1
- }
- }
- let noCheck = true // 是否可以选中
- // if(this.dataList.length > 0) {
- // this.dataList.forEach(item => {
- // if(item == d) {
- // noCheck = false
- // }
- // })
- // }
- return {
- dayNum: d,
- monthType: f,
- disabled: tDisabled, // 是否是当月
- noCheck: noCheck, // 是否可选
- toDay: toDay,
- nowDate: new Date(y, m - 1, d) // 当前日期
- }
- },
- getDaysSet(y, m) { // 获取某月显示的日期
- let year, month, firstWeek, daysNum, prevM, prevDiff, prevDaysNum, nextM,
- days = [] // 日期数据
- if(this.isDate(y)) {
- year = y.getFullYear()
- month = y.getMonth() + 1
- } else {
- year = Number(y)
- month = Number(m)
- }
- // 星期天则为7
- firstWeek = new Date(year, month - 1, 1).getDay() || 7
- prevDiff = firstWeek - this.startWeek
- daysNum = this.getDaysNum(year, month)
- prevM = this.getPrevMonth(year, month)
- prevDaysNum = this.getDaysNum(year, prevM.m)
- nextM = this.getNextMonth(year, month)
- // month flag
- let PREV_FLAG = 1,
- CURR_FLAG = 2,
- NEXT_FLAG = 3,
- count = 0
- // 上月最后几天
- for(let p = prevDaysNum - prevDiff + 1; p <= prevDaysNum; p++, count++) {
- days.push(this.getDayItem(prevM.y, prevM.m, p, PREV_FLAG))
- }
- // 本月天数
- for(let c = 1; c <= daysNum; c++, count++) {
- days.push(this.getDayItem(year, month, c, CURR_FLAG))
- }
- // 下月天数
- let c = (count % 7) === 0 ? count : (7 - (count % 7) + count)
- for (let n = 1, nl = c - count; n <= nl; n++) {
- days.push(this.getDayItem(nextM.y, nextM.m, n, NEXT_FLAG))
- }
- return days
- },
- getSmallCalendar(y, m, d) {
- let year, month, day, firstWeek,
- days = [] // 日期数据
- if(this.isDate(y)) {
- year = y.getFullYear()
- month = y.getMonth() + 1
- day = y.getDate()
- } else {
- year = Number(y)
- month = Number(m)
- day = Number(d)
- }
- let CURR_FLAG = 2,
- // NEXT_FLAG = 3,
- // PREV_FLAG = 1,
- count = 0
- // 星期天则为7
- firstWeek = new Date(year, month - 1, day).getDay() || 7
- // 在本周当天之前的日期
- for (let p = (firstWeek - 1); p > 0; p--, count++) {
- let tempD = new Date(year, month - 1, day - p)
- let pYear = tempD.getFullYear()
- let pMonth = tempD.getMonth() + 1
- let pDay = tempD.getDate()
- days.push(this.getDayItem(pYear, pMonth, pDay, CURR_FLAG))
- }
- // 当天日期
- days.push(this.getDayItem(year, month, day, CURR_FLAG))
- count++
- // 在本周当天之后的日期
- for (let n = 1; n <= (7 - count); n++) {
- let tempD = new Date(year, month - 1, day + n)
- let nYear = tempD.getFullYear()
- let nMonth = tempD.getMonth() + 1
- let nDay = tempD.getDate()
- days.push(this.getDayItem(nYear, nMonth, nDay, CURR_FLAG))
- }
- this.daySet.push(days)
- },
- slideChangeTransitionEnd() { // 滑动完成
- let swiper = this.swiper
- // 当前滑动到的日期
- let checkDate = this.daySet[swiper.activeIndex][6].nowDate
- this.curDays = {
- year: checkDate.getFullYear(),
- month: checkDate.getMonth() + 1
- }
- // 是否是第一页
- // if(swiper.isBeginning) { // 由于体验问题不使用
- // let tempDays = this.getDaysSet(new Date(this.curDays.year, this.curDays.month - 1))
- // this.daySet.unshift(tempDays)
- // }
- // 是否是最后一页
- if(swiper.isEnd) {
- this.daySet.push(this.getDaysSet(new Date(this.curDays.year, this.curDays.month)))
- }
- this.$emit('onChangeMonth', checkDate)
- },
- slidePrev() { // 上一页
- this.imgs.arrow1 = require('@/assets/images/arrow-active.png')
- this.swiper.slidePrev()
- },
- slideNext() { // 下一页
- this.imgs.arrow2 =require('@/assets/images/arrow-active.png')
- this.swiper.slideNext()
-
- },
- endTouch(){
- this.imgs.arrow1 = require('@/assets/images/arrow.png')
- this.imgs.arrow2 = require('@/assets/images/arrow.png')
- },
- touchStart() {
- let touch = event.touches[0]
- this.points.startY = touch.pageY
- this.points.startX = touch.pageX
- },
- touchMove() {
- // let touch = event.touches[0]
- // this.points.endX = touch.pageX
- // this.points.endY = touch.pageY
-
- // let pt = this.points,
- // X = pt.endX - pt.startX,
- // Y = pt.endY - pt.startY
- // if ( Math.abs(X) > Math.abs(Y) && X > 0 ) {
- // console.log("left 2 right");
- // }
- // else if ( Math.abs(X) > Math.abs(Y) && X < 0 ) {
- // console.log("right 2 left");
- // }
- // else
- // if ( Math.abs(Y) > Math.abs(X) && Y > 0) {
- // console.log("top 2 bottom")
- // this.onTouchDown()
- // }
- // else if ( Math.abs(Y) > Math.abs(X) && Y < 0 ) {
- // console.log("bottom 2 top")
- // this.onTouchUp()
- // }
- // else{
- // console.log("just touch");
- // }
- },
- onTouchUp() { // 向上滑
- // let activeIndex = this.swiper.activeIndex
- // let acitveDayIndex // 选中日期索引
- // let curDays = this.daySet[activeIndex]
- // curDays.forEach((day, index) => {
- // if(this.dateToString(day.nowDate) == this.dateToString(this.selectElement)) {
- // // console.log(index)
- // acitveDayIndex = index
- // }
- // })
- // let arr = []
- // for(let i = 0; i < 7; i++) {
- // arr.push({
- // dayNum: i + 1,
- // monthType: 2,
- // disabled: false,
- // toDay: i == 3 ? true : false,
- // nowDate: new Date()
- // })
- // }
- // console.log(arr)
- // this.daySet[activeIndex] = arr
- // this.$forceUpdate()
- // this.swiper.detachEvents() //移除所有slide监听事件
- // this.swiper.attachEvents() //重新绑定所有监听事件。
- // return {
- // dayNum: d,
- // monthType: f,
- // disabled: f === 2 ? 0 : 1, // 是否是当月
- // toDay: toDay,
- // nowDate: new Date(y, m - 1, d) // 当前日期
- // }
- },
- onTouchDown() { // 向下滑
- },
- touchEnd() {
- // let pt = this.points,
- // X = pt.endX - pt.startX,
- // Y = pt.endY - pt.startY
- // if ( Math.abs(X) > Math.abs(Y) && X > 0 ) {
- // console.log("left 2 right");
- // }
- // else if ( Math.abs(X) > Math.abs(Y) && X < 0 ) {
- // console.log("right 2 left");
- // }
- // else
- // if ( Math.abs(Y) > Math.abs(X) && Y > 0) {
- // console.log("top 2 bottom");
- // }
- // else if ( Math.abs(Y) > Math.abs(X) && Y < 0 ) {
- // console.log("bottom 2 top");
- // }
- // else{
- // console.log("just touch");
- // }
- },
- onSelectDay(item) {
- // 除了当月其它月份不能点击, 可选日期
- if(item.monthType == 2 && !item.noCheck) {
- this.selectElement = item.nowDate
- // 暴露出方法
- this.$emit('onSelectDay', item.nowDate)
- }
- },
- onToggleType() { //切换日历类型
- // this.calendarType = this.calendarType === 'default' ? 'small' : 'default'
- if(this.calendarType === 'default') {
- this.calendarType = 'small'
- this.getSmallCalendar(new Date())
- } else {
- this.calendarType = 'default'
- this.getListMonth()
- }
- this.$forceUpdate()
- }
- },
- computed: {
- swiper() {
- return this.$refs.mySwiper.swiper
- }
- },
- watch: {
- dayList(value) {
- this.dayDateList = value
- const selectDate = this.daySet[this.swiper.activeIndex]
- selectDate.forEach(item => {
- if(item.disabled == 0 && item.monthType == 2) {
- if(value.includes(dayjs(item.nowDate).format('DD'))) {
- item.noCheck = false
- } else {
- item.noCheck = true
- }
- }
- })
- }
- },
- mounted() {
- // 选择不同的日历类型
- if(this.calendarType == 'default') {
- this.getListMonth()
- } else {
- this.getSmallCalendar(new Date())
- }
- // current swiper instance
- // 然后你就可以使用当前上下文内的swiper对象去做你想做的事了
- // console.log('this is current swiper instance object', this.swiper)
- // this.swiper.slideTo(0, 1000, false)
- }
- }
- </script>
- <style lang='less' scoped>
- @import url("../assets/commonLess/variable.less");
- .calendar {
- background: @whiteColor;
- padding: .15rem .2rem;
- .c__hd {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .c__date {
- color: #333;
- font-size: .24rem;
- // font-weight: bold;
- // span {
- // padding-right: .08rem;
- // font-size: .26rem;
- // }
- }
- .van-icon {
- margin-left: .1rem;
- width: .24rem;
- height: .24rem;
- font-size: .14rem;
- color: #c4c4c4;
- background: #eee;
- text-align: center;
- line-height: .24rem;
- border-radius: 50%;
- transition: all .2s ease;
- &:active {
- background: @mColor;
- color: #4eada7;
- color: #fff;
- }
- }
- .week-title {
- display: flex;
- align-items: center;
- justify-content: space-between;
- text-align: center;
- padding: .2rem 0 .1rem;
- color: #777;
- span {
- flex: 1;
- font-size: .16rem;
- color: @tFontColor;
- font-weight: 600;
- }
- }
- .tr {
- display: flex;
- align-items: center;
- text-align: center;
- font-size: .15rem;
- color: @mFontColor;
- // justify-content: space-around;
- flex-wrap: wrap;
- }
- .td {
- width: 14.2857%;
- margin-top: .03rem;
- &.small {
- span {
- background: #F6F8F9;
- }
- }
- span {
- position: relative;
- display: block;
- margin: 0 auto;
- width: .36rem;
- height: .36rem;
- background: transparent;
- border-radius: 50%;
- line-height: .36rem;
- font-weight: 500;
- &.noCheck {
- color: #ccc;
- }
- &.today::before {
- content: '今';
- display: block;
- width: calc(100% - 2px);
- height: calc(100% - 2px);
- background: #fff;
- color: @orangeColor;
- border: 1px solid @orangeColor;
- border-radius: 50%;
- position: absolute;
- left: 0;
- top: 0;
- }
- &.active {
- background: @mColor;
- color: @whiteColor;
- transition: all .2s ease;
- }
- &.disabled { // 如果不是当月则不显示
- color: transparent !important;
- background: #fff !important;
- &::before {
- content: '';
- color: #fff;
- border: 1px solid #fff;
- }
- }
- }
- }
- .swiper-slide {
- transition: all .5s ease;
- }
- .arrow {
- width: .22rem;
- height: .22rem;
- }
- .arrow-left {
- transform: rotate(180deg);
- margin-right: .12rem;
- }
- }
- </style>
|