|
|
|
<template>
|
|
|
|
<div class="date-picker">
|
|
|
|
<div class="header">
|
|
|
|
<div class="current-date year-selector" v-if="view === 'month'" >
|
|
|
|
<button @click="prevYear"><</button>
|
|
|
|
<span @click="getMonYear">{{ currentYear !== selectedYear ? selectedYear : currentYear }}</span>
|
|
|
|
<button @click="nextYear">></button>
|
|
|
|
</div>
|
|
|
|
<div class="selectYear" v-if="view !== 'month'" >
|
|
|
|
<span class="year">{{view == 'monthTwo' ? '选择年份':'' }}</span>
|
|
|
|
</div>
|
|
|
|
<div class="controls">
|
|
|
|
<button v-if="!onlyYear" @click="toggleView('month')" :class="{ active: view !== 'year' }">月度</button>
|
|
|
|
<button @click="toggleView('year')" :class="{ active: view === 'year' }">年度</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="selector" v-if="view === 'month'">
|
|
|
|
|
|
|
|
<div class="month-grid">
|
|
|
|
<button
|
|
|
|
v-for="month in months"
|
|
|
|
:key="month.value"
|
|
|
|
@click="selectMonth(month.value)"
|
|
|
|
:class="{ active: month.value === currentMonth && currentYear === selectedYear }"
|
|
|
|
>
|
|
|
|
{{ month.label }}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="selector" v-if="view !== 'month'">
|
|
|
|
<div :class="[view == 'monthTwo' ? 'monthTwo-grid' :'','year-grid']">
|
|
|
|
<button
|
|
|
|
v-for="year in visibleYears"
|
|
|
|
:key="year"
|
|
|
|
@click="selectYear(year)"
|
|
|
|
:class="{
|
|
|
|
yearActive: year === currentYear,
|
|
|
|
current: year === new Date().getFullYear(),
|
|
|
|
}"
|
|
|
|
>
|
|
|
|
{{ year }}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
name: 'DatePicker',
|
|
|
|
props: {
|
|
|
|
modelValue: {
|
|
|
|
type: Date,
|
|
|
|
default: () => new Date()
|
|
|
|
},
|
|
|
|
view:{
|
|
|
|
type:String,
|
|
|
|
default:'month'
|
|
|
|
},
|
|
|
|
onlyYear:{
|
|
|
|
type:Boolean,
|
|
|
|
default:false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
// view: 'month', // 'month' or 'year monthTwo'
|
|
|
|
selectedYear: this.modelValue.getFullYear(),
|
|
|
|
currentMonth: this.modelValue.getMonth() + 1,
|
|
|
|
currentYear: this.modelValue.getFullYear(),
|
|
|
|
decadeStart: Math.floor(this.modelValue.getFullYear() / 10) * 10 - 6,
|
|
|
|
months: [
|
|
|
|
{ value: 1, label: '1月' },
|
|
|
|
{ value: 2, label: '2月' },
|
|
|
|
{ value: 3, label: '3月' },
|
|
|
|
{ value: 4, label: '4月' },
|
|
|
|
{ value: 5, label: '5月' },
|
|
|
|
{ value: 6, label: '6月' },
|
|
|
|
{ value: 7, label: '7月' },
|
|
|
|
{ value: 8, label: '8月' },
|
|
|
|
{ value: 9, label: '9月' },
|
|
|
|
{ value: 10, label: '10月' },
|
|
|
|
{ value: 11, label: '11月' },
|
|
|
|
{ value: 12, label: '12月' }
|
|
|
|
]
|
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
decadeEnd() {
|
|
|
|
return this.decadeStart + 9;
|
|
|
|
},
|
|
|
|
visibleYears() {
|
|
|
|
const years = [];
|
|
|
|
for (let i = 0; i < 12; i++) {
|
|
|
|
years.push(this.decadeStart + i);
|
|
|
|
}
|
|
|
|
return years;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
mounted(){
|
|
|
|
let selectedDate = new Date()
|
|
|
|
const oldDate = JSON.parse(localStorage.getItem('date'))
|
|
|
|
if(oldDate){
|
|
|
|
selectedDate = new Date(oldDate)
|
|
|
|
this.currentMonth = selectedDate.getMonth() + 1;
|
|
|
|
this.currentYear = selectedDate.getFullYear();
|
|
|
|
this.selectedYear = this.currentYear;
|
|
|
|
this.decadeStart = Math.floor(this.modelValue.getFullYear() / 10) * 10 - 6;
|
|
|
|
}else{
|
|
|
|
selectedDate = new Date()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
beforeUnmount() {
|
|
|
|
// 移除监听
|
|
|
|
// this.$emit('update-count', 'month')
|
|
|
|
},
|
|
|
|
destroyed(){
|
|
|
|
// this.$emit('update-count', 'month')
|
|
|
|
console.log('destroyed====');
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
getMonYear(){
|
|
|
|
this.$emit('update-count', 'monthTwo')
|
|
|
|
},
|
|
|
|
toggleView(viewType) {
|
|
|
|
this.$emit('update-count', viewType)
|
|
|
|
},
|
|
|
|
selectMonth(month) {
|
|
|
|
this.currentMonth = month;
|
|
|
|
this.currentYear = this.selectedYear;
|
|
|
|
this.$emit('update-count', 'month')
|
|
|
|
this.emitDate();
|
|
|
|
},
|
|
|
|
selectYear(year) {
|
|
|
|
this.selectedYear = year;
|
|
|
|
this.currentYear = this.selectedYear;
|
|
|
|
if(this.view == 'monthTwo'){
|
|
|
|
this.$emit('update-count', 'month')
|
|
|
|
}
|
|
|
|
this.emitDate();
|
|
|
|
},
|
|
|
|
prevYear() {
|
|
|
|
this.selectedYear--;
|
|
|
|
this.updateDecade();
|
|
|
|
},
|
|
|
|
nextYear() {
|
|
|
|
this.selectedYear++;
|
|
|
|
this.updateDecade();
|
|
|
|
},
|
|
|
|
prevDecade() {
|
|
|
|
this.decadeStart -= 10;
|
|
|
|
},
|
|
|
|
nextDecade() {
|
|
|
|
this.decadeStart += 10;
|
|
|
|
},
|
|
|
|
updateDecade() {
|
|
|
|
this.decadeStart = Math.floor(this.selectedYear / 10) * 10;
|
|
|
|
},
|
|
|
|
emitDate() {
|
|
|
|
const selectedDate = new Date(this.currentYear, this.currentMonth - 1, 1);
|
|
|
|
this.$emit('update:modelValue', selectedDate);
|
|
|
|
this.$emit('change', selectedDate);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
modelValue(newVal) {
|
|
|
|
let selectedDate = newVal
|
|
|
|
this.currentMonth = selectedDate.getMonth() + 1;
|
|
|
|
this.currentYear = selectedDate.getFullYear();
|
|
|
|
this.selectedYear = this.currentYear;
|
|
|
|
this.decadeStart = Math.floor(this.currentYear / 10) * 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.date-picker {
|
|
|
|
font-family: Microsoft YaHei UI;
|
|
|
|
width: 300px;
|
|
|
|
/* border: 1px solid #ddd; */
|
|
|
|
border-radius: 4px;
|
|
|
|
padding: 10px 0 0 0;
|
|
|
|
/* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); */
|
|
|
|
}
|
|
|
|
|
|
|
|
.header {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
margin-bottom: 8px;
|
|
|
|
padding-bottom: 8px;
|
|
|
|
border-bottom: 1px solid #F1F2F5;
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
color: #626573;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.current-date {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.selectYear{
|
|
|
|
font-size: 14px;
|
|
|
|
font-weight: normal;
|
|
|
|
line-height: normal;
|
|
|
|
text-align: center;
|
|
|
|
letter-spacing: 0.08em;
|
|
|
|
color: #006AFF;
|
|
|
|
}
|
|
|
|
.controls{
|
|
|
|
border-radius: 4px;
|
|
|
|
background: #EAECF0;
|
|
|
|
box-sizing: border-box;
|
|
|
|
border: 1px solid #EAECF0;
|
|
|
|
padding: 3px 6px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.selector{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.controls button {
|
|
|
|
background: none;
|
|
|
|
border: none;
|
|
|
|
padding: 1px 12px;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
.controls button.active {
|
|
|
|
background-color: #FFFFFF;
|
|
|
|
color: #006AFF;
|
|
|
|
/* border-color: #1890ff; */
|
|
|
|
}
|
|
|
|
|
|
|
|
.year-selector, .decade-selector {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
margin-bottom: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.year-selector button, .decade-selector button {
|
|
|
|
background: none;
|
|
|
|
border: none;
|
|
|
|
cursor: pointer;
|
|
|
|
font-size: 16px;
|
|
|
|
}
|
|
|
|
.year-selector{
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-grid, .year-grid {
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: repeat(4, 1fr);
|
|
|
|
gap: 5px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-grid button, .year-grid button {
|
|
|
|
font-family: Microsoft YaHei UI;
|
|
|
|
padding: 8px;
|
|
|
|
border: none;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
width: 48px;
|
|
|
|
background: none;
|
|
|
|
cursor: pointer;
|
|
|
|
border-radius: 20px;
|
|
|
|
color: #1E2226;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-grid button:hover, .year-grid button:hover {
|
|
|
|
background-color: #F2F7FF;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-grid button.active, .year-grid button.active,.year-grid button.yearActive{
|
|
|
|
background-color: #006AFF;
|
|
|
|
color: white !important;
|
|
|
|
}
|
|
|
|
.monthTwo-grid button.current {
|
|
|
|
/* background-color: #006AFF !important;
|
|
|
|
color: white !important;
|
|
|
|
border-color: #1890ff !important; */
|
|
|
|
color: #fff;
|
|
|
|
|
|
|
|
}
|
|
|
|
.year-grid button.current{
|
|
|
|
/* font-weight: bold; */
|
|
|
|
color: #006AFF;
|
|
|
|
/* background-color: #F2F7FF; */
|
|
|
|
/* border-color: #1890ff; */
|
|
|
|
}
|
|
|
|
</style>
|