写在前面的话,那天和自己说要一个星期发布一篇文章,不知不觉就又到了该写文章的日期了,我却一直没有准备好要写什么,想到之前项目中自己写的Calendar,总结还没有写。写这个项目要感谢"ciqulover"写的文章,我在写项目的时候参考了他写的Calendar,地址在这里React.js入门实践:一个酷酷的日历选择器组件,啰嗦完毕,我们开始吧!
首先看一下效果:
我们可以看到效果就是这样的,它主要实现了以下的一些功能:
- 可以选择日期
- 可以选择月份
- 会根据不同的服务器返回的日期状态显示不同的图标
- 超出时间外不可以切换日期
- 有一个隐藏显示动画
实现这个日历选择器最最重要的是想清楚它的数据是怎么来的,把这个想清楚后,我们就知道了应该怎么去表现它,因为那只是它背后数据的延伸和变现。
大家都知道一年有12月:
/**
* 年的对象
* @param year
* @returns {{year: *, months: Array}}
*/
const getYearInstance = (year)=>{
return {year, months:[]}
}
一个月有N
多天:
/**
*
* @param month 月
* @param year 年
* @returns {{month: *, days: Array}}
*/
const getMonthInstance = (month,year)=>{
return { month,year,days:[]};
}
一天有N
多数据,这些数据都是当天的一些状态,比如是否可以点击,是否是过去的日期,等等:
/**
* 日对象
* @param day 日
* @param month 月 已加1
* @param year 年
* @param timestamp 时间戳
* @param isCurrentMonth 是否是当前月,只有当前月份的日期可以点击
* @param isPost 是否是生日之前的日期
* @parm flag -1 默认值
* @returns {{day: *, month: *, year: *, week: number, isHaveData: boolean, isOnClick: boolean}}
*/
const getDayInstance = (day,month,year,isCurrentMonth=false,isPost = false)=>{
month = getMonth(month);
year = getYear(month,year);
let timestamp = parseInt(getTimestamp(year+'-'+month+'-'+day));
let week = new Date(year, month, day).getDay();
let months= month;
let days = day;
let flag = -1;
let isGetReport = false;
let _isFutureTime = isFutureTime(timestamp);
let isTodays = isToday(year,month,day);
if(month<10){
months = '0'+month;
}
if(day<10){
days = '0'+day;
}
let All_date = year+'-'+months+'-'+days;
return {day,month,year,week,timestamp,isCurrentMonth,All_date,isPost,flag,isTodays,isGetReport,_isFutureTime};
}
因为会设计到非常多的日期当天状态的判断,比如是否是过去的,是否是未来的,等等,所以这些状态都保存在了日的数据里,我们在判断的时候直接从这个日数据里判断就可以了,不用去在外部判断。
下一步是整合所有数据弄成年的数据:
//获取一年的数据
export const displayDaysPerMonth = (year)=>{
//定义每个月的天数,如果是闰年第二月改为29天
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
daysInMonth[1] = 29
}
let daysInPreviousMonth = [].concat(daysInMonth);
daysInPreviousMonth.unshift(daysInPreviousMonth.pop());
//获取每一个月显示数据中需要补足上个月的天数
let addDaysFromPreMonth = new Array(12)
.fill(null)
.map((item, index) => {
let day = new Date(year, index, 1).getDay();
if (day === 0) {
return 7
} else {
return day
}
});
let year_bean = getYearInstance(year);
for(let monthIndex = 0; monthIndex < 12;monthIndex++) {
let addDays = addDaysFromPreMonth[monthIndex],
daysCount = daysInMonth[monthIndex],
daysCountPrevious = daysInPreviousMonth[monthIndex],
monthData = [];
//定义当前月的对象,以保存当前月中日的数据
let month_bean = getMonthInstance(monthIndex+1,year);
//添加上个月补齐的数据
for (; addDays > 0; addDays--) {
let day_bean = getDayInstance(daysCountPrevious--,monthIndex,year,false);
monthData.unshift(day_bean)
}
//添加当月的数据
for (let i = 1; i <= daysCount;i++) {
let day_bean = getDayInstance(i,monthIndex+1,year,true);
monthData.push(day_bean)
}
//补足下一个月
for (let i = 42 - monthData.length, j = 0; j < i;) {
let day_bean = getDayInstance(++j,monthIndex+2,year,false);
monthData.push(day_bean)
}
month_bean.days.push(...monthData);
year_bean.months.push(month_bean);
}
// logger(year_bean);
return year_bean;
}
我们的日历显示的日期是42天,这其中需要补足上个月下个月的天数,因为是上个月和下个月的数据,所以他们的可点击是false
。
获取完年数据以后,我们就可以整合数据来显示界面了,这里我分开了两个View
来实现,Calendar
是总控,以及显示上面的切换月份那个tab
,CalendarMain
则是显示下面具体的日历选择器。
下面是Calendar
的代码,具体的逻辑我会在代码中写注释。
/**
* Created by jfy on 2018/1/22.
* 千里之行,始于足下!
* 1.建立数据
* 2.render
* 3.提供接口
*/
import React from 'react';
import {getTimestamp, getDate} from '../../../../utils/common';
import './style/Calendar.scss';
import CalendarMain from './CalendarMain';
function getImg(name, path='zgl/calendar') {
return `${window.global.config.static_file_host}/static/images/zrk_user_web/${path}/${name}.png`;
}
import {displayDaysPerMonth,changeMonthToDate,getCurrentData} from './DayUtils';
export default class Calendar extends React.Component{
constructor(props){
super(props)
const default_date = getDate(this.props.timestamp);
this.state = {
year: default_date.getFullYear(),
month: default_date.getMonth()+1,
day: default_date.getDate(),
viewData:this.props.viewData?this.props.viewData:displayDaysPerMonth(default_date.getFullYear()),
up_img_url:'up_month',
}
}
//当调用者的state发生改变时
componentWillReceiveProps(nextProps) {
if(nextProps.default_date) {
const default_date = getDate(getTimestamp(nextProps.default_date));
this.setState({
year: default_date.getFullYear(),
month: default_date.getMonth() + 1,
day: default_date.getDate(),
});
}
//判断是否有购买日期,如果有,则获取购买日期的年和月,在购买日期之前的按钮是不可以切换的
if(nextProps.purchasing_date){
let purchasing_date = nextProps.purchasing_date;
purchasing_date = getDate(getTimestamp(purchasing_date));
let month = purchasing_date.getMonth()+1;
let year = purchasing_date.getFullYear();
if(year === this.state.year && month === (this.state.month)){
this.setState({up_img_url:'up_month_gray'});
}else{
this.setState({up_img_url:'up_month'});
}
}
}
//初始化获取当前数据
componentDidMount(){
let data = getCurrentData(this.state.year,this.state.month,this.state.day);
this.onChangeDateListener(data);
}
//获取日历状态
getReportDailyStatus(data){
this.props.getReportDailyStatus(data,this.state.viewData);
}
//当时间发生改变时
onChangeDateListener(data){
this.getReportDailyStatus(data);
this.props.onChangeDateListener(data,this.state.viewData);
}
//切换到下一个月
nextMonth(){
this.setState({up_img_url:'up_month'});
let data = changeMonthToDate(this.state.year,this.state.month,this.state.day,true);
let viewData = displayDaysPerMonth(data.year);
this.setState({
year: data.year,
month: data.month,
day:data.day,
viewData:viewData
}, ()=>{
this.onChangeDateListener(data);
})
}
//切换到上一个月
prevMonth() {
let purchasing_date = this.props.purchasing_date;
purchasing_date = getDate(getTimestamp(purchasing_date));
let month = purchasing_date.getMonth()+1;
let year = purchasing_date.getFullYear();
if(year === this.state.year && (month === (this.state.month-1) || month === (this.state.month))){
this.setState({up_img_url:'up_month_gray'});
}else{
this.setState({up_img_url:'up_month'});
}
if(year === this.state.year && month === this.state.month ){
return ;
}
let data = changeMonthToDate(this.state.year,this.state.month,this.state.day,false);
let viewData = displayDaysPerMonth(data.year);
this.setState({
year: data.year,
month: data.month,
day:data.day,
viewData:viewData
}, ()=>{
this.onChangeDateListener(data);
})
}
//选择日期
onDatePickListener(day) {
this.setState({day})
}
render(){
let props = {
viewData: this.state.viewData
};
return (
<div className="base_column">
<div ref = 'Head' className="calendar_title_layout" onClick={this.datePickerToggle.bind(this)}>
<img id="prevMonth" className="calendar_img" src={getImg(this.state.up_img_url)} onClick={this.prevMonth.bind(this)} />
<div className="calendar_title">{this.state.year +'年'+ (this.state.month<10?'0'+this.state.month:this.state.month) +'月'+ (this.state.day<10?'0'+this.state.day:this.state.day) +'日'}</div>
<img id="nextMonth" className="calendar_img" src={getImg('down_month')} onClick={this.nextMonth.bind(this)}/>
</div>
<CalendarMain {...props}
ref = 'CalendarMain'
onDatePickListener = {this.onDatePickListener.bind(this)}
onChangeDateListener = {this.onChangeDateListener.bind(this)}
year={this.state.year}
month={this.state.month}
day={this.state.day}
/>
</div>
);
}
}
我们在切换日期之后,调用接口来进行相应的改变,或者是重新获取数据来刷新页面。
比如上面的:
//切换到下一个月
nextMonth(){
this.setState({up_img_url:'up_month'});
let data = changeMonthToDate(this.state.year,this.state.month,this.state.day,true);
let viewData = displayDaysPerMonth(data.year);
this.setState({
year: data.year,
month: data.month,
day:data.day,
viewData:viewData
}, ()=>{
this.onChangeDateListener(data);
})
}
切换到上个月因为需要判断是否可以切换日期,所以多了很多代码。
//切换到上一个月
prevMonth() {
let purchasing_date = this.props.purchasing_date;
purchasing_date = getDate(getTimestamp(purchasing_date));
let month = purchasing_date.getMonth()+1;
let year = purchasing_date.getFullYear();
if(year === this.state.year && (month === (this.state.month-1) || month === (this.state.month))){
this.setState({up_img_url:'up_month_gray'});
}else{
this.setState({up_img_url:'up_month'});
}
if(year === this.state.year && month === this.state.month ){
return ;
}
let data = changeMonthToDate(this.state.year,this.state.month,this.state.day,false);
let viewData = displayDaysPerMonth(data.year);
this.setState({
year: data.year,
month: data.month,
day:data.day,
viewData:viewData
}, ()=>{
this.onChangeDateListener(data);
})
}
这里最主要的是时间的改变的跟新:当外部设置时间时,我们需要更随Props
来更新时间。
//当调用者的state发生改变时
componentWillReceiveProps(nextProps) {
if(nextProps.default_date) {
const default_date = getDate(getTimestamp(nextProps.default_date));
this.setState({
year: default_date.getFullYear(),
month: default_date.getMonth() + 1,
day: default_date.getDate(),
});
}
if(nextProps.purchasing_date){
let purchasing_date = nextProps.purchasing_date;
purchasing_date = getDate(getTimestamp(purchasing_date));
let month = purchasing_date.getMonth()+1;
let year = purchasing_date.getFullYear();
if(year === this.state.year && month === (this.state.month)){
this.setState({up_img_url:'up_month_gray'});
}else{
this.setState({up_img_url:'up_month'});
}
}
}
最后我们看CalendarMain
的调用:
<CalendarMain {...props}
ref = 'CalendarMain'
onDatePickListener = {this.onDatePickListener.bind(this)}
onChangeDateListener = {this.onChangeDateListener.bind(this)}
year={this.state.year}
month={this.state.month}
day={this.state.day}
/>
我们给它传入了两个接口,当时间选中和当时间切换的时候,还有当前的年月日。
我们的日期显示是先日后六的,所以定义了
week_names: ['日', '一', '二', '三', '四', '五', '六'],
日历显示是横向的7天,竖向的6行,所以我们的数据显示这里还需要进行一次切割。让它能够竖向的遍历六次,横向的遍历7次。
//获取当前月显示数据
getCurrentMonth() {
let view_data = this.props.viewData;
let current_month_data = view_data.months[this.props.month-1].days;
let rowsInMonth = [];
current_month_data.forEach((day, index) => {
if (index % 7 === 0) {
rowsInMonth.push(current_month_data.slice(index, index + 7))
}
});
return rowsInMonth;
}
在代码里我们看到的遍历是这样的。
_renderMain() {
let current_month_data = this.getCurrentMonth();
return (
<div className="main" ref='main' >
{
current_month_data.map((row, rowindex) => {
return (
<div key={rowindex} className="calendar_box_row" ref={'row_'+rowindex} style={{height:45}}>
{
row.map((data, index) => {
return (
<div className={data.isCurrentMonth && !data._isFutureTime ? 'calendar_box_current_month' : 'calendar_box_other_month'}
key={data.All_date}
onClick={this.onDatePickListener.bind(this, data,'row_'+rowindex)}
>
{
this._renderViewCurrentDay(data)
}
</div>
);
})
}
</div>
)
})
}
</div>
);
}
具体的日期状态显示在this._renderViewCurrentDay(data)
;
隐藏动画的实现需要判断今天是哪天,今天是在哪一行,我们根据在哪一行来获取需要进行动画的位置。
//获取当前日期在第几行
getCurrentRowIndex(){
let current_month_data = this.getCurrentMonth();
for(let [index,data] of current_month_data.entries()){
for(let value of data){
if(value.day===this.props.day && value.month === this.props.month){
return index;
}
}
}
}
我们调用动画
datePickerToggle() {
let row_data = ['row_0','row_1','row_2','row_3','row_4','row_5'];
//确定是在哪一行
for(let row of row_data){
if(row!==this.state.current_rowIndex){
this.refs[row].style.height = this.refs[row].style.height === '45px'? '0px':'45px';
}
}
if(this.state.current_status==='bottom_arrow'){
this.setState({current_status:'top_arrow'});
}else{
this.setState({current_status:'bottom_arrow'});
}
}
CalendarMain
的代码:
/**
* Created by jfy on 2018/1/22.
* 千里之行,始于足下!
*/
import React from 'react';
import './style/Calendar.scss';
function getImg(name, path='zgl/calendar') {
return `${window.global.config.static_file_host}/static/images/zrk_user_web/${path}/${name}.png`;
}
export default class CalendarMain extends React.Component {
constructor(props) {
super(props)
this.state = {
current_day:this.props.year+''+this.props.month+''+ this.props.day,
week_names: ['日', '一', '二', '三', '四', '五', '六'],
current_rowIndex:'row_'+this.getCurrentRowIndex(),
current_status:'top_arrow'
}
}
//当调用者的state发生改变时
componentWillReceiveProps(nextProps) {
if(nextProps.year||nextProps.month||nextProps.day) {
this.setState({
current_day: nextProps.year+''+nextProps.month+''+nextProps.day
});
}
}
//获取当前月显示数据
getCurrentMonth() {
let view_data = this.props.viewData;
let current_month_data = view_data.months[this.props.month-1].days;
let rowsInMonth = [];
current_month_data.forEach((day, index) => {
if (index % 7 === 0) {
rowsInMonth.push(current_month_data.slice(index, index + 7))
}
});
return rowsInMonth;
}
//获取当前日期在第几行
getCurrentRowIndex(){
let current_month_data = this.getCurrentMonth();
for(let [index,data] of current_month_data.entries()){
for(let value of data){
if(value.day===this.props.day && value.month === this.props.month){
return index;
}
}
}
}
//选择日期
onDatePickListener(data,rowindex,evn) {
evn.preventDefault();
let days = data.year+''+data.month+''+data.day;
if (days !== this.state.current_day && data.isCurrentMonth) {
this.props.onDatePickListener(data.day);
if (data.isHaveData) {
this.props.onChangeDateListener(data);
}
this.setState({
current_day:days,
current_rowIndex:rowindex
});
this.props.onChangeDateListener(data);
}
}
//星期标题
_renderWeekHeader() {
return (
<div className="calendar_header_row" ref="header" style={{height:45}}>
{
this.state.week_names.map((name, index) => {
return (
<div className="calendar_box" key={index}>
{name}
</div>
)
})
}
</div>
);
}
datePickerToggle() {
let row_data = ['row_0','row_1','row_2','row_3','row_4','row_5'];
//确定是在哪一行
for(let row of row_data){
if(row!==this.state.current_rowIndex){
this.refs[row].style.height = this.refs[row].style.height === '45px'? '0px':'45px';
}
}
if(this.state.current_status==='bottom_arrow'){
this.setState({current_status:'top_arrow'});
}else{
this.setState({current_status:'bottom_arrow'});
}
}
componentDidMount(){
setTimeout(()=>{
this.datePickerToggle()
},500)
}
//其他日期的效果
_renderViewItem(data){
if(data.isGetReport){
return (
<div style={{ backgroundImage: `url('${getImg('birthday_icon')}')`, backgroundSize: 'contain'}} className="calendar_box_hava_data">
<span style={{color:'#fff'}}>{data.day}</span>
</div>
)
}
switch (data.flag){
//不可以修改
case 1:
if(data.isTodays){
return (
<div className="calendar_box_click_red">
{data.day}
</div>
)
}else{
return (
<div style={{ backgroundImage: `url('${getImg('hava_data')}')`, backgroundSize: 'contain'}} className="calendar_box_hava_data">
</div>
)
}
case 2:
if(data.isTodays){
return (
<div className="calendar_box_click_red">
{data.day}
</div>
)
}else{
return (
<div className="calendar_box_other_gray">
{data.day}
</div>
)
}
//显示补
case 3:
case 4:
case 6:
case 7:
return (
<div style={{ backgroundImage: `url('${getImg('no_hava_data')}')`, backgroundSize: 'contain'}} className="calendar_box_hava_data">
</div>
)
//显示对勾
case 5:
case 8:
return (
<div style={{ backgroundImage: `url('${getImg('hava_data')}')`, backgroundSize: 'contain'}} className="calendar_box_hava_data">
</div>
)
//显示未来
case 9:
return (
<div className="calendar_box_furture">
{data.day}
</div>
)
default:
if(data.isTodays){
return (
<div className="calendar_box_click_red">
{data.day}
</div>
)
}else{
return (
<div className="calendar_box_other_gray">
{data.day}
</div>
)
}
}
}
_renderViewCurrentDay(data){
if(this.state.current_day===(data.year+''+data.month+''+data.day)){
if(data.isTodays){
return (
<div className="calendar_box_click_red">
{data.day}
</div>
)
}
switch (data.flag){
case 3:
case 4:
case 6:
case 7:
return (
<div className="calendar_box_click_red">
{data.day}
</div>
)
default:
return (
<div className="calendar_box_click_blue">
{data.day}
</div>
)
}
}else{
return this._renderViewItem(data);
}
}
_renderMain() {
let current_month_data = this.getCurrentMonth();
return (
<div className="main" ref='main' >
{
current_month_data.map((row, rowindex) => {
return (
<div key={rowindex} className="calendar_box_row" ref={'row_'+rowindex} style={{height:45}}>
{
row.map((data, index) => {
return (
<div className={data.isCurrentMonth && !data._isFutureTime ? 'calendar_box_current_month' : 'calendar_box_other_month'}
key={data.All_date}
onClick={this.onDatePickListener.bind(this, data,'row_'+rowindex)}
>
{
this._renderViewCurrentDay(data)
}
</div>
);
})
}
</div>
)
})
}
</div>
);
}
render() {
let view_data = this.props.viewData;
return (
<div className="calendar_layout" >
{this._renderWeekHeader()}
{this._renderMain()}
<div className="calendar_status_layout" onClick={this.datePickerToggle.bind(this)}>
<div className="base_row_align_center">
<img src={getImg('bu_icon')} className="calendar_box_icon"/>
<p>未填写</p>
</div>
<img className="calendar_status_icon" src={getImg(this.state.current_status)}/>
<div className="base_row_align_center">
<div style={{ backgroundImage: `url('${getImg('report_icon')}')`, backgroundSize: 'contain'}} className="calendar_box_icon">
<span style={{color:'#fff'}}>{view_data.birthday_day}</span>
</div>
<p>出报告日</p>
</div>
</div>
</div>
);
}
}
最后是Scss
的代码:
@import "../../../static/css/commons/base_layout";
.additional_layout{
@extend .base_column;
}
.additional_layout_row{
@extend .base_row;
}
.additional_item_layout_v1{
@extend .base_center;
@extend %flex;
background-color: rgba(249,184,91,0.1);
height: 120px;
margin: 5px;
position: relative;
}
.additional_item_layout_v2{
@extend .additional_item_layout_v1;
background-color: rgba(236,129,126,0.1);
}
.additional_item_layout_v3{
@extend .additional_item_layout_v1;
background-color: rgba(147,208,133,0.1);
}
.additional_item_layout_v4{
@extend .additional_item_layout_v1;
background-color: rgba(122,106,241,0.1);
}
.additional_item_layout_v5{
@extend .additional_item_layout_v1;
background-color: rgba(255,227,76,0.1);
}
.additional_item_layout_v6{
@extend .additional_item_layout_v1;
background-color: rgba(125,158,240,0.1);
}
.additional_icon{
width: 41px;
height: 41px;
}
.additional_count_p{
position: absolute;
bottom: 5px;
right: 5px;
}
.additional_icon_last{
width: 75px;
height: 75px;
}
.additional_item_last_layout{
@extend .base_center;
width: 75px;
height: 75px;
}
.additional_item_last_layout p{
font-size: 13px;
color: #8e8e8e;
}
.additional_future_content{
@extend .base_column_align_center;
}
.additional_future_icon{
height: 110px;
width: 118px;
margin-top: 25px;
}
.additional_future_content p {
font-size: 15px;
color: #5e5e5e;
margin-top: 20px;
}
.additional_modal_content{
@extend .base_column_align_center;
position: relative;
}
.additional_modal_close_img{
position: absolute;
width: 15px;
height: 15px;
top:0px;
right: 0px;
}
.additional_modal_icon{
height: 150px;
width: 85.5px;
margin-top: 16px;
}
.additional_modal_p{
font-size: 15px;
color: #5e5e5e;
margin-top: 15px;
}
.button_layout{
@extend .base_row_justify_space-between;
padding: 15px 0px;
}
.button {
@extend .base_center;
height: 35px;
background-color: #ffb544;
border-radius: 50px;
padding: 5px 15px;
}
.button2 {
@extend .base_center;
height: 35px;
background-color: $buttonColor;
border-radius: 50px;
padding: 2px 10px;
margin-left: 10px;
}
.button p{
font-size: 11px;
color: white;
}
.button2 p{
font-size: 11px;
color: white;
}
.additional_show_layout {
width: auto !important;
height: auto
}
补充一份文件,就是上面的scss
文件继承的base_layout.scss
;
//基础布局文件
@import "base";
%flex{
flex: 1;
-webkit-flex: 1;
}
.base {
display: flex;
display: -webkit-flex;
}
//横向布局
.base_row {
@extend .base;
flex-direction: row; -webkit-flex-direction: row;
}
//竖向布局
.base_column{
@extend .base;
flex-direction: column; -webkit-flex-direction: column;
}
@mixin justify-content($layout:center){
justify-content: $layout;
-webkit-justify-content: $layout;
}
@mixin align-items($layout:center){
align-items: $layout;
-webkit-align-items: $layout;
}
@mixin get_font_size($fontSize:14px){
font-size: $fontSize;
}
//竖向居中对齐
.base_column_justify_center {
@extend .base_column;
@include justify-content(center);
}
//横向居中对齐
.base_row_justify_center {
@extend .base_row;
@include justify-content(center);
}
//竖向垂直居中齐
.base_column_align_center {
@extend .base_column;
@include align-items(center);
}
//横向垂直居中对齐
.base_row_align_center {
@extend .base_row;
@include align-items(center);
}
//居中
.base_center {
@extend .base;
@include justify-content(center);
@include align-items(center);
}
.base_row_justify_space-between{
@extend .base_row;
@include justify-content(space-between);
}
.base_row_title_layout{
@extend .base_row_align_center;
@include justify-content(space-between);
}
//页面container根布局
.page_container {
flex: 1;
-webkit-flex: 1;
flex-direction: column; -webkit-flex-direction: column;
display: flex;
display: -webkit-flex;
background: $backgroundColor;
font-size: 15px;
}
.page_context {
@extend .base_column;
@extend %flex;
overflow: scroll;
overflow-scrolling: touch;
-webkit-overflow-scrolling: touch;
padding-bottom: 10px;
overflow-x: hidden;
}
//如果有需要,自己添加...
base.scss
文件是一份颜色文件。
/**
* 字体和颜色,基础布局的base文件
*/
//字体大小
$remindTitleSize:20px;
$navigationSize:18px;
$contentSize:17px;
$buttonSize:16px;
$tabFontSize:15px;
$minorSize:14px;
$smalltitleSize:13px;
$smallerSize:12px;
$assistSize:11px;
//颜色
$white:#fff;
$assistColor:#c1c1c1;
$minorColor:#8e8e8e;
$contentColor:#5e5e5e;
$remindColor:#ee5765;
$buttonColor:#7d9ef0;
$backgroundColor:#f0f0f0;
$lineColor:#e8e8e8;
$headerTextColor:#5c5c5c;
$titleColor:#333333;
$circleColor:#FFF9c6;
补充答应大家的函数:
/**
* Created by jfy on 2018/1/23.
* 千里之行,始于足下!
*/
/**
* 年的对象
* @param year
* @returns {{year: *, months: Array}}
*/
const getYearInstance = (year)=>{
return {year, months:[]}
}
/**
*
* @param month 月
* @param year 年
* @returns {{month: *, days: Array}}
*/
const getMonthInstance = (month,year)=>{
return { month,year,days:[]};
}
/**
* 日对象
* @param day 日
* @param month 月 已加1
* @param year 年
* @param timestamp 时间戳
* @param isCurrentMonth 是否是当前月,只有当前月份的日期可以点击
* @parm flag -1 默认值
* @returns {{day: *, month: *, year: *, week: number, isOnClick: boolean}}
*/
const getDayInstance = (day,month,year,isCurrentMonth=false,isPost = false)=>{
year = getYear(month,year);
month = getMonth(month);
let date = new Date();
let hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
let minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let second =date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
let time = " "+hour+":"+minute+":"+second;
let current_date = year+'-'+month+'-'+day;
let current_timestamp = parseInt(Commons.getTimestamp(current_date+time,1));
let timestamp = parseInt(Commons.getTimestamp(current_date,1));
let start_timestamp = parseInt(Commons.getTimestamp(current_date+" 00:00:00",1));
let end_timestamp = parseInt(Commons.getTimestamp(current_date+" 23:59:59",1));
let week = new Date(year, month, day).getDay();
let months= month;
let days = day;
let flag = -1;
let _isFutureTime = isFutureTime(timestamp);
let isTodays = isToday(year,month,day);
if(month<10){
months = '0'+month;
}
if(day<10){
days = '0'+day;
}
let All_date = year+'-'+months+'-'+days;
return {day,month,year,week,current_timestamp,timestamp,start_timestamp,end_timestamp,isCurrentMonth,All_date,isPost,flag,isTodays,_isFutureTime};
}
//获取month
const getMonth = (month) =>{
if(month==0){
return 12;
}else if(month ==13){
return 1;
}
return month;
}
//获取year
const getYear = (month,year)=>{
if(month==0){
return --year;
}else if(month ==13){
return ++year;
}
return year;
}
//获取一年的数据
export const displayDaysPerMonth = (year)=>{
//定义每个月的天数,如果是闰年第二月改为29天
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
daysInMonth[1] = 29
}
let daysInPreviousMonth = [].concat(daysInMonth);
daysInPreviousMonth.unshift(daysInPreviousMonth.pop());
//获取每一个月显示数据中需要补足上个月的天数
let addDaysFromPreMonth = new Array(12)
.fill(null)
.map((item, index) => {
let day = new Date(year, index, 1).getDay();
if (day === 0) {
return 7
} else {
return day
}
});
let year_bean = getYearInstance(year);
for(let monthIndex = 0; monthIndex < 12;monthIndex++) {
let addDays = addDaysFromPreMonth[monthIndex],
daysCount = daysInMonth[monthIndex],
daysCountPrevious = daysInPreviousMonth[monthIndex],
monthData = [];
//定义当前月的对象,以保存当前月中日的数据
let month_bean = getMonthInstance(monthIndex+1,year);
//添加上个月补齐的数据
for (; addDays > 0; addDays--) {
let day_bean = getDayInstance(daysCountPrevious--,monthIndex,year,false);
monthData.unshift(day_bean)
}
//添加当月的数据
for (let i = 1; i <= daysCount;i++) {
let day_bean = getDayInstance(i,monthIndex+1,year,true);
monthData.push(day_bean)
}
//补足下一个月
for (let i = 42 - monthData.length, j = 0; j < i;) {
let day_bean = getDayInstance(++j,monthIndex+2,year,false);
monthData.push(day_bean)
}
month_bean.days.push(...monthData);
year_bean.months.push(month_bean);
}
return year_bean;
}
/**
* 切换月份的日期切换,month和year是切换前的
* @param month
* @param year
* @param isNext true 下一个月 false 上一个月
*/
export const changeMonthToDate = (year,month,day,isNext=false)=>{
if(isNext){
if (month === 12) {
month =1;
year++;
} else {
month++;
}
}else {
if(month === 1){
month = 12;
year--;
}else{
month--;
}
}
day = handleDay(day,month,year);
return getDayInstance(day,month,year);
}
/**
* 获取当前数据
* @param year
* @param month
* @param day
* @returns {{year: *, month: *, day: *, timestamp: Number}}
*/
export const getCurrentData = (year,month,day)=>{
return getDayInstance(day,month,year);
}
/**
*
* @param day
* @param oldMonth 切换前的月
* @param newMonth 切换后的月
* @param year 切换后的年
* @returns {*}
*/
export const handleDay = (day,newMonth,year)=>{
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
daysInMonth[1] = 29
}
if(daysInMonth.indexOf(day)!==-1){
day = daysInMonth[--newMonth];
}
return day;
}
//是否是今天
export const isToday=(year,month,day)=>{
let all_date = year+'-'+month+'-'+day;
let todaysDate = new Date();
let years = todaysDate.getFullYear();
let months = todaysDate.getMonth()+1;
let days = todaysDate.getDate();
let all_dates = years+'-'+months+'-'+days;
return all_dates === all_date;
}
//是否是同一天
export const isToday_V2 = (all_date,date)=>{
let _date = date.toString().replace(/-/g, "/");
_date = new Date(_date);
let years = _date.getFullYear();
let months = _date.getMonth()+1;
let days = _date.getDate();
let all_dates = years+''+months+''+days;
return all_date === all_dates;
}
//判断时间是否是未来
export const isFutureTime=(timestamp)=>{
return timestamp>Commons.getTimestamp();
}
写到这里Over...