寫(xiě)在前面的話,那天和自己說(shuō)要一個(gè)星期發(fā)布一篇文章脓鹃,不知不覺(jué)就又到了該寫(xiě)文章的日期了逸尖,我卻一直沒(méi)有準(zhǔn)備好要寫(xiě)什么,想到之前項(xiàng)目中自己寫(xiě)的Calendar,總結(jié)還沒(méi)有寫(xiě)娇跟。寫(xiě)這個(gè)項(xiàng)目要感謝"ciqulover"寫(xiě)的文章岩齿,我在寫(xiě)項(xiàng)目的時(shí)候參考了他寫(xiě)的Calendar,地址在這里React.js入門(mén)實(shí)踐:一個(gè)酷酷的日歷選擇器組件,啰嗦完畢苞俘,我們開(kāi)始吧盹沈!
首先看一下效果:
我們可以看到效果就是這樣的,它主要實(shí)現(xiàn)了以下的一些功能:
- 可以選擇日期
- 可以選擇月份
- 會(huì)根據(jù)不同的服務(wù)器返回的日期狀態(tài)顯示不同的圖標(biāo)
- 超出時(shí)間外不可以切換日期
- 有一個(gè)隱藏顯示動(dòng)畫(huà)
實(shí)現(xiàn)這個(gè)日歷選擇器最最重要的是想清楚它的數(shù)據(jù)是怎么來(lái)的吃谣,把這個(gè)想清楚后乞封,我們就知道了應(yīng)該怎么去表現(xiàn)它,因?yàn)槟侵皇撬澈髷?shù)據(jù)的延伸和變現(xiàn)岗憋。
大家都知道一年有12月:
/**
* 年的對(duì)象
* @param year
* @returns {{year: *, months: Array}}
*/
const getYearInstance = (year)=>{
return {year, months:[]}
}
一個(gè)月有N
多天:
/**
*
* @param month 月
* @param year 年
* @returns {{month: *, days: Array}}
*/
const getMonthInstance = (month,year)=>{
return { month,year,days:[]};
}
一天有N
多數(shù)據(jù)肃晚,這些數(shù)據(jù)都是當(dāng)天的一些狀態(tài),比如是否可以點(diǎn)擊仔戈,是否是過(guò)去的日期关串,等等:
/**
* 日對(duì)象
* @param day 日
* @param month 月 已加1
* @param year 年
* @param timestamp 時(shí)間戳
* @param isCurrentMonth 是否是當(dāng)前月,只有當(dāng)前月份的日期可以點(diǎn)擊
* @param isPost 是否是生日之前的日期
* @parm flag -1 默認(rèn)值
* @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};
}
因?yàn)闀?huì)設(shè)計(jì)到非常多的日期當(dāng)天狀態(tài)的判斷监徘,比如是否是過(guò)去的晋修,是否是未來(lái)的,等等凰盔,所以這些狀態(tài)都保存在了日的數(shù)據(jù)里墓卦,我們?cè)谂袛嗟臅r(shí)候直接從這個(gè)日數(shù)據(jù)里判斷就可以了,不用去在外部判斷廊蜒。
下一步是整合所有數(shù)據(jù)弄成年的數(shù)據(jù):
//獲取一年的數(shù)據(jù)
export const displayDaysPerMonth = (year)=>{
//定義每個(gè)月的天數(shù)趴拧,如果是閏年第二月改為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());
//獲取每一個(gè)月顯示數(shù)據(jù)中需要補(bǔ)足上個(gè)月的天數(shù)
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 = [];
//定義當(dāng)前月的對(duì)象,以保存當(dāng)前月中日的數(shù)據(jù)
let month_bean = getMonthInstance(monthIndex+1,year);
//添加上個(gè)月補(bǔ)齊的數(shù)據(jù)
for (; addDays > 0; addDays--) {
let day_bean = getDayInstance(daysCountPrevious--,monthIndex,year,false);
monthData.unshift(day_bean)
}
//添加當(dāng)月的數(shù)據(jù)
for (let i = 1; i <= daysCount;i++) {
let day_bean = getDayInstance(i,monthIndex+1,year,true);
monthData.push(day_bean)
}
//補(bǔ)足下一個(gè)月
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天山叮,這其中需要補(bǔ)足上個(gè)月下個(gè)月的天數(shù)著榴,因?yàn)槭巧蟼€(gè)月和下個(gè)月的數(shù)據(jù),所以他們的可點(diǎn)擊是false
屁倔。
獲取完年數(shù)據(jù)以后脑又,我們就可以整合數(shù)據(jù)來(lái)顯示界面了,這里我分開(kāi)了兩個(gè)View
來(lái)實(shí)現(xiàn)锐借,Calendar
是總控问麸,以及顯示上面的切換月份那個(gè)tab
,CalendarMain
則是顯示下面具體的日歷選擇器钞翔。
下面是Calendar
的代碼严卖,具體的邏輯我會(huì)在代碼中寫(xiě)注釋。
/**
* Created by jfy on 2018/1/22.
* 千里之行布轿,始于足下哮笆!
* 1.建立數(shù)據(jù)
* 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',
}
}
//當(dāng)調(diào)用者的state發(fā)生改變時(shí)
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(),
});
}
//判斷是否有購(gòu)買(mǎi)日期来颤,如果有,則獲取購(gòu)買(mǎi)日期的年和月稠肘,在購(gòu)買(mǎi)日期之前的按鈕是不可以切換的
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'});
}
}
}
//初始化獲取當(dāng)前數(shù)據(jù)
componentDidMount(){
let data = getCurrentData(this.state.year,this.state.month,this.state.day);
this.onChangeDateListener(data);
}
//獲取日歷狀態(tài)
getReportDailyStatus(data){
this.props.getReportDailyStatus(data,this.state.viewData);
}
//當(dāng)時(shí)間發(fā)生改變時(shí)
onChangeDateListener(data){
this.getReportDailyStatus(data);
this.props.onChangeDateListener(data,this.state.viewData);
}
//切換到下一個(gè)月
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);
})
}
//切換到上一個(gè)月
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>
);
}
}
我們?cè)谇袚Q日期之后福铅,調(diào)用接口來(lái)進(jìn)行相應(yīng)的改變,或者是重新獲取數(shù)據(jù)來(lái)刷新頁(yè)面项阴。
比如上面的:
//切換到下一個(gè)月
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);
})
}
切換到上個(gè)月因?yàn)樾枰袛嗍欠窨梢郧袚Q日期滑黔,所以多了很多代碼。
//切換到上一個(gè)月
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);
})
}
這里最主要的是時(shí)間的改變的跟新:當(dāng)外部設(shè)置時(shí)間時(shí)环揽,我們需要更隨Props
來(lái)更新時(shí)間略荡。
//當(dāng)調(diào)用者的state發(fā)生改變時(shí)
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
的調(diào)用:
<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}
/>
我們給它傳入了兩個(gè)接口,當(dāng)時(shí)間選中和當(dāng)時(shí)間切換的時(shí)候薯演,還有當(dāng)前的年月日撞芍。
我們的日期顯示是先日后六的,所以定義了
week_names: ['日', '一', '二', '三', '四', '五', '六'],
日歷顯示是橫向的7天跨扮,豎向的6行序无,所以我們的數(shù)據(jù)顯示這里還需要進(jìn)行一次切割。讓它能夠豎向的遍歷六次衡创,橫向的遍歷7次帝嗡。
//獲取當(dāng)前月顯示數(shù)據(jù)
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>
);
}
具體的日期狀態(tài)顯示在this._renderViewCurrentDay(data)
;
隱藏動(dòng)畫(huà)的實(shí)現(xiàn)需要判斷今天是哪天璃氢,今天是在哪一行哟玷,我們根據(jù)在哪一行來(lái)獲取需要進(jìn)行動(dòng)畫(huà)的位置。
//獲取當(dāng)前日期在第幾行
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;
}
}
}
}
我們調(diào)用動(dòng)畫(huà)
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'
}
}
//當(dāng)調(diào)用者的state發(fā)生改變時(shí)
componentWillReceiveProps(nextProps) {
if(nextProps.year||nextProps.month||nextProps.day) {
this.setState({
current_day: nextProps.year+''+nextProps.month+''+nextProps.day
});
}
}
//獲取當(dāng)前月顯示數(shù)據(jù)
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;
}
//獲取當(dāng)前日期在第幾行
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);
}
}
//星期標(biāo)題
_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>
)
}
//顯示補(bǔ)
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>
)
//顯示對(duì)勾
case 5:
case 8:
return (
<div style={{ backgroundImage: `url('${getImg('hava_data')}')`, backgroundSize: 'contain'}} className="calendar_box_hava_data">
</div>
)
//顯示未來(lái)
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>未填寫(xiě)</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>出報(bào)告日</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
}
補(bǔ)充一份文件,就是上面的scss
文件繼承的base_layout.scss
椰苟;
//基礎(chǔ)布局文件
@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;
}
//豎向居中對(duì)齊
.base_column_justify_center {
@extend .base_column;
@include justify-content(center);
}
//橫向居中對(duì)齊
.base_row_justify_center {
@extend .base_row;
@include justify-content(center);
}
//豎向垂直居中齊
.base_column_align_center {
@extend .base_column;
@include align-items(center);
}
//橫向垂直居中對(duì)齊
.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);
}
//頁(yè)面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
文件是一份顏色文件。
/**
* 字體和顏色舆蝴,基礎(chǔ)布局的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;
補(bǔ)充答應(yīng)大家的函數(shù):
/**
* Created by jfy on 2018/1/23.
* 千里之行谦絮,始于足下!
*/
/**
* 年的對(duì)象
* @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:[]};
}
/**
* 日對(duì)象
* @param day 日
* @param month 月 已加1
* @param year 年
* @param timestamp 時(shí)間戳
* @param isCurrentMonth 是否是當(dāng)前月洁仗,只有當(dāng)前月份的日期可以點(diǎn)擊
* @parm flag -1 默認(rèn)值
* @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;
}
//獲取一年的數(shù)據(jù)
export const displayDaysPerMonth = (year)=>{
//定義每個(gè)月的天數(shù)层皱,如果是閏年第二月改為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());
//獲取每一個(gè)月顯示數(shù)據(jù)中需要補(bǔ)足上個(gè)月的天數(shù)
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 = [];
//定義當(dāng)前月的對(duì)象,以保存當(dāng)前月中日的數(shù)據(jù)
let month_bean = getMonthInstance(monthIndex+1,year);
//添加上個(gè)月補(bǔ)齊的數(shù)據(jù)
for (; addDays > 0; addDays--) {
let day_bean = getDayInstance(daysCountPrevious--,monthIndex,year,false);
monthData.unshift(day_bean)
}
//添加當(dāng)月的數(shù)據(jù)
for (let i = 1; i <= daysCount;i++) {
let day_bean = getDayInstance(i,monthIndex+1,year,true);
monthData.push(day_bean)
}
//補(bǔ)足下一個(gè)月
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 下一個(gè)月 false 上一個(gè)月
*/
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);
}
/**
* 獲取當(dāng)前數(shù)據(jù)
* @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;
}
//判斷時(shí)間是否是未來(lái)
export const isFutureTime=(timestamp)=>{
return timestamp>Commons.getTimestamp();
}
寫(xiě)到這里Over...