今天小编给大家分享一下vue怎么实现左右滑动选择日期组件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
效果图:
1、安装dayjs日期文件
npm install dayjs --save
2、封装的组件:
<template>
<div class="m-calendar" ref="calendar">
<div class="m-toolbar">
<div class="m-year-selector">
<!-- <a class="m-prev-btn" @click="changeYear('prev')"></a> -->
<span>{{showDate.year}}{{yearName}}</span>
<!-- <a class="m-next-btn" @click="changeYear('next')"></a> -->
</div>
<div class="m-month-selector">
<!-- <a class="m-prev-btn" @click="changeMonth('prev')"></a> -->
<span>{{monthNames[showDate.month-1]}}</span>
<!-- <a class="m-next-btn" @click="changeMonth('next')"></a> -->
</div>
</div>
<div class="m-week-header">
<div
class="m-week-day"
v-for="item in weekNames"
:key="item"
>
{{item}}
</div>
</div>
<div
class="m-months-container"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
>
<div
class="m-months-wrapper"
:
>
<div
class="m-months"
v-for="(month,monthIndex) in fullDate"
:key="monthIndex"
:style="{
transform: `translate3d(${(monthIndex-1+translateX + (isTouching ? touch.x : 0))*100}%, 0, 0)`,
transitionDuration: isTouching ? '0s' : '.3s',
}"
>
<div
class="m-row"
v-for="(week,weekIndex) in month"
:key="weekIndex"
>
<div
class="m-day"
v-for="(day,dayIndex) in week"
:key="dayIndex"
@click="onDayClick(day)"
>
<span
:class="{
'm-day-num':true,
'm-grey': day.isGrey,
'm-today': day.isToday,
'm-disable': day.isDisable,
'm-select': day.isSelect,
}"
>
<!-- 'm-during': day.isDuring -->
{{day.value}}
</span>
<slot name="day" :date="day" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import dayjs from 'dayjs';
let touchStartPosition;
let touchEndPosition;
let timeStamp;
export default {
name: 'inlineCalendar',
props: {
defaultDate: {
type: [Date, Number, Array, String, dayjs],
},
disabledDate: {
type: Array,
default() {
return [];
},
},
minDate: {
type: [Date, Number, Array, String, dayjs],
},
maxDate: {
type: [Date, Number, Array, String, dayjs],
},
mode: {
type: String,
default: 'single',
},
dayClick: {
type: Function,
default() {
return function() {
return true;
};
},
},
enableTouch: {
type: Boolean,
default: true,
},
monthNames: {
type: Array,
default() {
return ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
},
},
weekNames: {
type: Array,
default() {
return ['一', '二', '三', '四', '五', '六', '日'];
},
},
yearName: {
type: String,
default: '年',
},
restrictCurrentMonth: {
type: Boolean,
default: false,
},
},
watch: {
mode() {
this.init();
},
},
data() {
return {
fullDate: [[], [], []],
translateX: 0,
showDate: {
year: undefined,
month: undefined,
},
dateNow: {
year: dayjs().year(),
month: dayjs().month() + 1,
date: dayjs().date(),
},
selectDate: [],
touch: {
x: 0,
y: 0,
},
isTouching: false,
};
},
created() {
this.init();
},
methods: {
init(date) {
this.selectDate = [];
let { defaultDate, mode } = this;
if (date) {
defaultDate = date;
}
let dateToShow = dayjs().startOf('month');
if (mode === 'single' && defaultDate) {
this.selectDate = dayjs(defaultDate).startOf('day');
dateToShow = this.selectDate.startOf('month');
}
if (mode === 'multiple' && Array.isArray(defaultDate)) {
if (defaultDate.length > 0) {
this.selectDate = defaultDate.map((item) => dayjs(item).startOf('day'));
}
}
if (mode === 'during' && Array.isArray(defaultDate)) {
if (defaultDate.length === 2) {
const startDate = dayjs(defaultDate[0]).startOf('day');
const endDate = dayjs(defaultDate[1]).startOf('day');
if (startDate.isBefore(endDate) || startDate.isSame(endDate)) {
this.selectDate = [startDate, endDate];
}
}
}
this.showDate = {
year: dateToShow.year(),
month: dateToShow.month() + 1,
};
this.getFullDate(this.showDate);
},
touchstart(event) {
if (this.enableTouch) {
touchStartPosition = event.touches[0].clientX;
touchEndPosition = event.touches[0].clientY;
timeStamp = event.timeStamp;
this.touch = {
x: 0,
y: 0,
};
this.isTouching = true;
}
},
touchmove(event) {
if (this.enableTouch) {
this.touch = {
x: (event.touches[0].clientX - touchStartPosition) / this.$refs.calendar.offsetWidth,
y: (event.touches[0].clientY - touchEndPosition) / this.$refs.calendar.offsetHeight,
};
}
},
touchend(event) {
if (this.enableTouch) {
this.isTouching = false;
const during = dayjs(event.timeStamp).diff(timeStamp);
if (Math.abs(this.touch.x) > Math.abs(this.touch.y) && Math.abs(this.touch.x * this.$refs.calendar.offsetWidth) > 20) {
if (this.touch.x > 0) {
this.changeMonth('prev');
} else if (this.touch.x < 0) {
this.changeMonth('next');
}
} else {
this.touch = {
x: 0,
y: 0,
};
}
}
},
// 触发change事件
emitChange() {
this.$emit('change', this.selectDate);
},
// 触发切换年月事件
emitSwitch(showDate) {
if (this.restrictCurrentMonth) {
this.selectDate = [];
}
this.$emit('switch', showDate);
},
// 日期点击事件
onDayClick(day) {
if (!this.dayClick(day.dateTime)) {
return;
}
switch (this.$props.mode) {
case 'single':
if (!day.isSelect && !day.isDisable) {
this.selectDate = day.dateTime;
this.getFullDate(this.showDate);
this.emitChange();
}
break;
case 'multiple':
if (!day.isSelect && !day.isDisable) {
this.selectDate.push(day.dateTime);
this.getFullDate(this.showDate);
this.emitChange();
} else {
if (this.selectDate.length > 1) {
this.selectDate = this.selectDate.filter((item) => !item.isSame(day.dateTime));
this.getFullDate(this.showDate);
this.emitChange();
}
}
break;
case 'during':
if (day.isDisable) return;
if (this.restrictCurrentMonth && day.isGrey) return;
if (this.selectDate.length === 0) {
this.selectDate = [day.dateTime];
} else if (this.selectDate.length === 1) {
this.selectDate.push(day.dateTime);
if (this.selectDate[1].isBefore(this.selectDate[0])) {
this.selectDate.reverse();
}
} else if (this.selectDate.length === 2) {
this.selectDate = [day.dateTime];
}
this.getFullDate(this.showDate);
this.emitChange();
break;
}
},
// 切换年份
changeYear(action) {
const date = dayjs(`${this.showDate.year}-${this.showDate.month}`);
let computedDate;
switch (action) {
case 'prev':
this.translateX += 1;
computedDate = date.subtract(1, 'year');
break;
case 'next':
this.translateX -= 1;
computedDate = date.add(1, 'year');
break;
}
this.showDate = {
year: computedDate.year(),
month: computedDate.month() + 1,
};
this.emitSwitch(this.showDate);
this.getFullDate(this.showDate);
},
// 切换月份
changeMonth(action) {
const date = dayjs(`${this.showDate.year}-${this.showDate.month}`);
let computedDate;
switch (action) {
case 'prev':
this.translateX += 1;
computedDate = date.subtract(1, 'month');
break;
case 'next':
this.translateX -= 1;
computedDate = date.add(1, 'month');
break;
}
this.showDate = {
year: computedDate.year(),
month: computedDate.month() + 1,
};
this.emitSwitch(this.showDate);
this.getFullDate(this.showDate);
},
// 暴露出去的方法:切换已选的时间
changeDate(date) {
if (dayjs(date).isValid() || Array.isArray(date)) {
this.init(date);
} else {
console.error('Type of parameter is invalid!');
}
},
// 暴露出去的方法:切换当前显示的时间
changeDateView(date = dayjs()) {
const changeDate = dayjs(date);
this.showDate = {
year: changeDate.year(),
month: changeDate.month() + 1,
};
this.getFullDate(this.showDate);
},
getFullDate() {
const date = dayjs(`${this.showDate.year}-${this.showDate.month}`);
const thisDate = this.getDate(date);
const prevDate = this.getDate(date.subtract(1, 'month'));
const nextDate = this.getDate(date.add(1, 'month'));
this.fullDate = [
prevDate.fullDate,
thisDate.fullDate,
nextDate.fullDate,
];
},
// 当前日期是否被选中
isSelect(date) {
// console.log(date)
let select = false;
switch (this.$props.mode) {
case 'single':
if (this.selectDate && date.isSame(this.selectDate)) {
select = true;
}
break;
case 'multiple':
if (this.selectDate.length > 0 && this.selectDate.some((item) => date.isSame(item))) {
select = true;
}
break;
}
return select;
},
// 当前时间是否在selectDate之间
isBetting(date) {
if (this.mode === 'during') {
const startDate = this.selectDate[0];
const endDate = this.selectDate[1];
if (this.selectDate.length === 1) {
return date.isSame(startDate);
} else if (this.selectDate.length === 2) {
return (date.isAfter(startDate) && date.isBefore(endDate)) || date.isSame(startDate) || date.isSame(endDate);
}
}
return false;
},
getIsDisable(dateTime) {
let isDisable = false;
const disabledDate = this.disabledDate.map((item) => dayjs(item).startOf('day'));
if (this.minDate || this.maxDate) {
if (this.minDate) {
const minDate = dayjs(this.minDate).startOf('day');
isDisable = dateTime.isBefore(minDate);
}
if (!isDisable && this.maxDate) {
const maxDate = dayjs(this.maxDate).endOf('day');
isDisable = dateTime.isAfter(maxDate);
}
} else if (disabledDate.length > 0) {
if (this.mode !== 'during') {
isDisable = disabledDate.some((item) => item.isSame(dateTime));
}
}
return isDisable;
},
getDate(thisDate) {
let date = [];
const prevDate = thisDate.subtract(1, 'month');
const nextDate = thisDate.add(1, 'month');
const firstDayOfWeek = thisDate.day() || 7;
const dayCountOfThisMonth = thisDate.daysInMonth();
const dayCountOfPrevMonth = prevDate.daysInMonth();
const prevIndexOfThisMonth = firstDayOfWeek - 1;
const NextIndexOfThisMonth = firstDayOfWeek + dayCountOfThisMonth - 2;
const disabledDate = this.disabledDate.map((item) => dayjs(item).startOf('day'));
for (let i = 0; i < 7 * 6; i++) {
// 上月
if (i < prevIndexOfThisMonth) {
const value = dayCountOfPrevMonth - (firstDayOfWeek - i - 2);
const dateTime = prevDate.date(value);
date[i] = {
value,
dateTime,
isGrey: true,
isToday: dateTime.isSame(dayjs().startOf('day')),
isSelect: this.isSelect(dateTime),
isDisable: this.getIsDisable(dateTime),
isDuring: this.isBetting(dateTime),
};
}
// 当月
if (
i >= prevIndexOfThisMonth &&
i <= NextIndexOfThisMonth
) {
const value = i - firstDayOfWeek + 2;
const dateTime = thisDate.date(value);
date[i] = {
value,
dateTime,
isGrey: false,
isToday: dateTime.isSame(dayjs().startOf('day')),
isSelect: this.isSelect(dateTime),
isDisable: this.getIsDisable(dateTime),
isDuring: this.isBetting(dateTime),
};
}
// 下月
if (i > NextIndexOfThisMonth) {
const value = i - firstDayOfWeek - dayCountOfThisMonth + 2;
const dateTime = nextDate.date(value);
date[i] = {
value,
dateTime,
isGrey: true,
isToday: dateTime.isSame(dayjs().startOf('day')),
isSelect: this.isSelect(dateTime),
isDisable: this.getIsDisable(dateTime),
isDuring: this.isBetting(dateTime),
};
}
}
const fullDate = [];
for (let i = 0; i < 6; i++) {
fullDate.push(date.slice(i * 7, (i + 1) * 7));
}
return {
fullDate,
};
},
},
};
</script>
<style lang="less" scoped>
@import './style.css';
</style>
相关的style.css文件
.m-calendar {
background: #fff;
box-shadow: 0px 2px 6px 0px rgba(183, 183, 183, 0.2);
}
.m-calendar .m-toolbar {
padding-bottom: 0.36266667rem;
}
.m-calendar .m-toolbar {
display: flex;
height: 2.56rem;
}
.m-calendar .m-toolbar .m-month-selector,
.m-calendar .m-toolbar .m-year-selector {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 0.74666667rem;
}
.m-calendar .m-toolbar .m-month-selector,
.m-calendar .m-toolbar .m-year-selector {
line-height: 1.06666667rem;
}
.m-calendar .m-toolbar .m-month-selector,
.m-calendar .m-toolbar .m-year-selector {
font-size: 0.768rem;
font-family: PingFangSC-Medium, PingFangSC;
font-weight: 500;
color: #29262a;
}
.m-calendar .m-toolbar .m-year-selector {
padding-left: 0.91733333rem;
}
.m-calendar .m-week-header {
padding: 0 0.91733333rem;
}
.m-calendar .m-week-header {
padding-bottom: 0.512rem;
}
.m-calendar .m-week-header {
position: relative;
display: flex;
box-sizing: border-box;
justify-content: space-between;
font-size: 0.59733333rem;
}
.m-calendar .m-week-header .m-week-day {
text-align: left;
line-height: 0.85333333rem;
font-family: PingFangSC-Regular, PingFangSC;
font-weight: 400;
color: #222222;
}
.m-calendar .m-months-container {
position: relative;
box-sizing: border-box;
height: 12.37333333rem;
overflow: hidden;
}
.m-calendar .m-months-container .m-months-wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.m-calendar .m-months-container .m-months-wrapper .m-months {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
will-change: transform;
width: 16rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row {
padding-top: 0.512rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row {
width: 16rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row {
position: relative;
display: flex;
height: 1.408rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day {
margin-right: 0.87466667rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day:nth-child(1) {
margin-left: 0.66133333rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day {
font-size: 0.59733333rem;
font-family: PingFangSC-Medium, PingFangSC;
font-weight: 500;
color: #222222;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day {
position: relative;
height: 1.408rem;
width: 1.408rem;
line-height: 1.408rem;
text-align: center;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
border-radius: 50%;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-day-num {
width: 1.408rem;
display: inline-block;
border-radius: 100%;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-day-num {
height: 1.408rem;
line-height: 1.408rem;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-grey {
color: #b8b8b8;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-today {
background: #5DABF3;
color: #fff;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-disable {
color: #b8b8b8;
text-decoration: line-through;
}
.m-calendar .m-months-container .m-months-wrapper .m-months .m-row .m-day .m-select {
background: #007aff;
color: #fff;
}
3、使用到的页面
<div class="data">
<inlineCalendar :dayClick="dayClick" />
</div>
<script>
import inlineCalendar from '../components/inlineCalendar';
export default {
name: "home",
data() {
return { };
},
components: {
inlineCalendar
},
methods: {
dayClick(date) {
console.log('date---->', date);
console.log(date.format('YYYY-MM-DD'));
let dates = date.format('YYYY-MM-DD');
},
}
};
</script>
<style lang="less" scoped>
.data {
position: fixed;
top: 1.87733333rem;
width: 100%;
height: 100%;
}
</style>
以上就是“vue怎么实现左右滑动选择日期组件”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。