- Vue DatePicker
- 设计思路
- 子组件的代码
- 父组件内的应用
- 父组件向子组件传值
- 首次渲染及props和data的利用
- 父组件二次传值及渲染
- 子组件向父组件传值
- 子组件内设置传值的事件名称及要传的数据
- 父组件调用该事件获取新值
- 总结
Vue DatePicker
设计思路
假设我们想做一个简约(简陋)的日期选择组件,用三个 <select></select>
元素来完成一个日期选择功能,UI参考下图。
需要做到的功能有:
- 年份选择要可以限制范围
- 日子选择需要和年份和月份联动,自动变成28天、29天、30天或31天
- 从父组件点开不同来源的数据详情,每次都渲染一个新日期到子组件上去
- 手动更改日期后,可以回传给父组件,以便更新父组件的数据源
子组件的代码
<template>
<div>
<select v-model="yearVal" @change="getDateVal">
<option v-for="(year, i) in yearOption" :key="i">{{ year }}</option>
</select>
年
<select v-model="monthVal" @change="getDateVal">
<option v-for="(month, i) in monthOption" :key="i">{{ month }}</option>
</select>
月
<select v-model="dayVal" @change="getDateVal">
<option v-for="(day, i) in dayOption" :key="i">{{ day }}</option>
</select>
日
</div>
</template>
var monthOption = ["01", "02", "03", "04", "05", "06", "07", "08", "09", 10, 11, 12];
var _28dayOption = ["01", "02", "03", "04", "05", "06", "07", "08", "09",10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28];
var _29dayOption = _28dayOption.concat([29]);
var _30dayOption = _29dayOption.concat([30]);
var _31dayOption = _30dayOption.concat([31]);
export default {
name: "DatePickerUnit",
//按理说props应该设置类型什么的,但是我为了书写方便,
//选项里又有数字又有字符串,如果限定了类型,可能不太好统一。
props: ["startYear", "endYear", "year", "month", "day"],
data() {
return {
monthOption,
yearVal: this.year,
monthVal: this.month,
dayVal: this.day
};
},
computed: {
yearOption() {
//初始年份为过去10年
//如果有传参,则输出从开始年份到结束年份
var date = new Date();
var yearNow = date.getFullYear();
var startYear = this.startYear ? this.startYear : yearNow - 10;
var endYear = this.endYear ? this.endYear : yearNow;
var result = [];
for (let i = 0; i < endYear - startYear + 1; i++) {
result.push(startYear + i);
}
return result;
},
dayOption() {
var year = this.yearVal;
var month = this.monthVal;
var day = this.dayVal;
var month31day = ["01", "03", "05", "07", "08", 10, 12];
var month30day = ["04", "06", "09", 11];
//1,3,5,7,8,10,12月
for (let i = 0; i < month31day.length; i++) {
if (month == month31day[i]) {
return _31dayOption;
}
}
//4,6,9,11月
for (let i = 0; i < month30day.length; i++) {
if (month == month30day[i]) {
if (day == 31) {
//之前选了31日,本月没有,所以清空选择
this.dayVal = "";
}
return _30dayOption;
}
}
//2月
if ((0 == year % 4 && 0 != year % 100) || 0 == year % 400) {
//闰年2月
if (day > 29) {
//之前选的日子大于29,本月只有29天,所以清空选择
this.dayVal = "";
}
return _29dayOption;
} else {
//普通2月
if (day > 28) {
//之前选的日子大于28,本月只有28天,所以清空选择
this.dayVal = "";
}
return _28dayOption;
}
}
},
methods: {
getDateVal() {
//定义事件名称和要传的值,后面可以在父组件进行调用
this.$emit("dateChanged", {
year: this.yearVal,
month: this.monthVal,
day: this.dayVal
});
}
},
watch: {
//父组件再次给props传值时,如果没有watch,就不会接收第二次
year(newYear) {
this.yearVal = newYear;
},
month(newMonth) {
this.monthVal = newMonth;
},
day(newDay) {
this.dayVal = newDay;
}
}
};
父组件内的应用
<DatePickerUnit @dateChanged="changeBillDate"
:startYear="startYear" :endYear="endYear"
:year="billDateYear" :month="billDateMonth" :day="billDateDay"
></DatePickerUnit>
import DatePickerUnit from "~/components/Date-Picker-Unit";
export default {
components: ["DatePickerUnit"],
data() {
return {
startYear: 2013,
endYear: 2023,
billDateYear: 2023,
billDateMonth: "07",
billDateDay: 17
}
},
methods: {
changeBillDate(dateObj) {
this.billDateYear = dateObj.year;
this.billDateMonth = dateObj.month;
this.billDateDay = dateObj.day;
}
}
}
父组件向子组件传值
首次渲染及props和data的利用
我们在父组件里定义了子组件需要的5个 props
对应的 data
,此时会渲染第一次。
startYear
和 endYear
渲染完一次就够了,不涉及到父子组件双向传值,所以不用理它们。
year
month
day
这三个值,我们希望能在渲染到 <select></select>
之后,在用户手动选择选项的时候触发三个值的更改。
但是子组件的 props
是不能被赋予新值的,所以我们需要在子组件的 data
里新建3个值,yearVal
monthVal
dayVal
,在 data
里获取到 props
的值之后,再渲染到 html
里。
后续我们可以在子组件里触发 data
的更改,就可以二次渲染了。
父组件二次传值及渲染
如果父组件的 data
的值有变化,子组件是不会感应到的,props
第一次获取到的值不会随之改变,所以我们需要在子组件里设置 watch
来监听父组件的数据变化。监听到之后,就可以让子组件显示新的一组数据了。
子组件向父组件传值
子组件内设置传值的事件名称及要传的数据
当点开下拉菜单选择选项的时候,触发传值事件
<template>
<div>
<select @change="getDateVal">
...
</select>
</div>
</template>
methods: {
getDateVal() {
//定义事件名称和要传的值,后面可以在父组件进行调用
this.$emit("dateChanged", {
year: this.yearVal,
month: this.monthVal,
day: this.dayVal
});
}
}
父组件调用该事件获取新值
当子组件发生 dateChanged
事件的时候,父组件调用 changeBillDate
方法获取子组件的值
<DatePickerUnit @dateChanged="changeBillDate"
></DatePickerUnit>
methods: {
changeBillDate(dateObj) {
this.billDateYear = dateObj.year;
this.billDateMonth = dateObj.month;
this.billDateDay = dateObj.day;
}
}
然后就可以更新父组件的数据了。
总结
虽然是个简陋的功能,但是也是能用的呢。
全文完。