Skip to content

Commit 1a8e8ef

Browse files
committed
feat(calendar): show year select boxes above calendar
add showYearSelect API to support year select boxes above calendars to jump to a specific year
1 parent 794a660 commit 1a8e8ef

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

src/components/Calendar.vue

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55
<th class="prev available" @click="$emit('clickPrevMonth')">
66
<i :class="[arrowLeftClass]"></i>
77
</th>
8-
<th colspan="5" class="month">{{ monthName }} {{ year }}</th>
8+
<th colspan="5" class="month">
9+
{{ monthName }}
10+
<!-- select year start -->
11+
<select class="yearselect" v-model="activeYear" v-if="picker.showYearSelect">
12+
<option v-for="(year, index) in RangeOfYear" :value="year" :key="index">{{year}}</option>
13+
</select>
14+
<span v-else>{{ activeYear }}</span>
15+
<!-- select year end -->
16+
</th>
917
<th class="next available" @click="$emit('clickNextMonth')">
1018
<i :class="[arrowRightClass]"></i>
1119
</th>
@@ -34,15 +42,27 @@
3442
</template>
3543

3644
<script>
37-
import moment from "moment";
45+
import moment,{ min } from "moment";
3846
3947
function clean(momentDate) {
4048
return momentDate.clone().hour(0).minute(0).second(0).millisecond(0);
4149
}
4250
51+
// _.range([start=0], end, [step=1])
52+
function range(start=0, end, step=1) {
53+
const arr = [];
54+
start = +start;
55+
end = +end;
56+
for (let i = start; i<=end; i=i+step) {
57+
arr.push(i);
58+
}
59+
return arr;
60+
}
61+
4362
export default {
4463
name: "calendar",
45-
props: ["calendarMonth", "locale", "hoverStart", "hoverEnd", "start", "end"],
64+
inject: ['picker'],
65+
props: ["location", "calendarMonth", "locale", "hoverStart", "hoverEnd", "start", "end"],
4666
methods: {
4767
dayClass(date) {
4868
let dt = date.clone();
@@ -147,7 +167,30 @@ export default {
147167
}
148168
149169
return calendar;
150-
}
170+
},
171+
// if show year select
172+
RangeOfYear () {
173+
if (!this.picker.showYearSelect) return [];
174+
// TODO 这边因为依赖计算属性:this.calendar 那么是否需要处理 this.calendar[1]为空的情况?
175+
// const currentYear = this.calendar[1][1].year();
176+
177+
const picker = this.picker;
178+
const maxYear = (picker.maxDate && picker.maxDate.year()) || picker.maxYear;
179+
const minYear = (picker.minDate && picker.minDate.year()) || picker.minYear;
180+
return range(minYear, maxYear, 1);
181+
},
182+
activeYear: {
183+
get() {
184+
return this.calendarMonth.year();
185+
},
186+
set(newYear) {
187+
const calendarMonth = moment([newYear, this.month]);
188+
this.$emit('clickYearSelect', {
189+
location: this.location,
190+
calendarMonth,
191+
});
192+
},
193+
},
151194
},
152195
filters: {
153196
dateNum(value) {

src/components/Picker.vue

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
></calendar-ranges>
2323
<calendar
2424
class="calendar left"
25+
location="left"
2526
:calendar-month="inside__leftCalendarMonth"
2627
:locale="locale"
2728
:start="inside__start"
@@ -32,9 +33,11 @@
3233
@clickPrevMonth="clickPrevMonth"
3334
@dateClick="dateClick"
3435
@hoverDate="hoverDate"
36+
@clickYearSelect="clickYearSelect"
3537
></calendar>
3638
<calendar
3739
class="calendar right"
40+
location="right"
3841
:calendar-month="inside__rightCalendarMonth"
3942
:locale="locale"
4043
:start="inside__start"
@@ -45,6 +48,7 @@
4548
@clickPrevMonth="clickPrevMonth"
4649
@dateClick="dateClick"
4750
@hoverDate="hoverDate"
51+
@clickYearSelect="clickYearSelect"
4852
></calendar>
4953
</div>
5054
</transition>
@@ -93,6 +97,18 @@ export default {
9397
type: Boolean,
9498
default: false,
9599
},
100+
showYearSelect: {
101+
type: Boolean,
102+
default: false,
103+
},
104+
minYear: {
105+
type: String,
106+
default: moment().subtract(100, 'year').format('YYYY'),
107+
},
108+
maxYear: {
109+
type: String,
110+
default: moment().add(100, 'year').format('YYYY'),
111+
},
96112
},
97113
data() {
98114
let data = {
@@ -111,7 +127,9 @@ export default {
111127
};
112128
// TODO 这里的 props 究竟是放在 data 里面进行初始化好,还是放在生命周期中好呢?
113129
// https://github.com/ly525/blog/issues/252
130+
// https://github.com/ly525/blog/issues/258
114131
data.inside__leftCalendarMonth = moment(this.startDate);
132+
data.inside__rightCalendarMonth = moment(this.endDate);
115133
data.inside__start = moment(this.startDate);
116134
data.inside__end = moment(this.endDate);
117135
data.inside__hoverStart = moment(this.startDate);
@@ -130,6 +148,9 @@ export default {
130148
return data;
131149
},
132150
methods: {
151+
clickYearSelect({location, calendarMonth}) {
152+
this[`inside__${location}CalendarMonth`] = calendarMonth.clone();
153+
},
133154
clickNextMonth() {
134155
// TODO 如果有 linkedCalendars,需要更新代码
135156
// moment.js 的 add 和 sub tract 的改变自身的行为没有被 watch 到,原因是什么呢?
@@ -196,9 +217,6 @@ export default {
196217
}
197218
},
198219
computed: {
199-
inside__rightCalendarMonth() {
200-
return this.inside__leftCalendarMonth.clone().add(1, 'month')
201-
},
202220
startText() {
203221
return this.inside__start.format(this.locale.format);
204222
},
@@ -217,6 +235,12 @@ export default {
217235
inside__start (value) {
218236
this.inside__leftCalendarMonth = value.clone();
219237
},
238+
inside__leftCalendarMonth: {
239+
handler(leftMonth) {
240+
this.inside__rightCalendarMonth = leftMonth.clone().add(1, 'month');
241+
},
242+
immediate: true,
243+
},
220244
startDate(value) {
221245
this.inside__start = moment(value);
222246
},

src/styles/components/calendar.scss

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ table {
2121
border: 1px solid transparent;
2222
white-space: nowrap;
2323
cursor: pointer;
24-
25-
&:hover {
26-
background-color: #eee;
27-
border-color: transparent;
28-
color: inherit;
29-
}
3024
}
3125
}
3226
td {
27+
&:hover {
28+
background-color: #eee;
29+
border-color: transparent;
30+
color: inherit;
31+
}
3332
&.today {
3433
font-weight: bold;
3534
}

0 commit comments

Comments
 (0)