7 changed files with 6844 additions and 3052 deletions
File diff suppressed because it is too large
@ -0,0 +1,293 @@ |
|||
<template> |
|||
<div class="date-picker"> |
|||
<div class="header"> |
|||
<div class="current-date year-selector" v-if="view === 'month'" > |
|||
<button><</button> |
|||
<span @click="getMonYear">{{ currentYear !== selectedYear ? selectedYear : currentYear }}</span> |
|||
<button>></button> |
|||
</div> |
|||
<div class="selectYear" v-if="view !== 'month'" > |
|||
<span class="year">{{view == 'monthTwo' ? '选择年份':'' }}</span> |
|||
</div> |
|||
<div class="controls"> |
|||
<button @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' |
|||
} |
|||
}, |
|||
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, |
|||
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.currentYear / 10) * 10; |
|||
}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> |
Loading…
Reference in new issue