UNPKG

xcandy

Version:
168 lines (163 loc) 7.08 kB
import Nerv, { PureComponent } from "nervjs"; import dayjs from 'dayjs'; import classNames from 'classnames'; import { View } from '@tarojs/components'; import XcArrow from '../Arrow'; import { computePreMonthRenderArr, computeCurrenMonthRenderArr, computeNexMonthRenderArr } from './utils'; import RenderDatePro from './RenderDatePro'; import './index.scss'; class XcCalendar extends PureComponent { constructor() { super(...arguments); this.state = { renderDate: dayjs(), preMonthRenderArr: [], nextMonthRenderArr: [], isStartMonth: false, isEndMonth: false, currentMonthRenderArrPro: [] }; this.renderNewMonth = () => { const { renderDate } = this.state; const { start, end } = this.props; let isStartMonth = false; let isEndMonth = false; const renderDateMonthStart = renderDate.startOf('month'); const preMonthRenderArr = computePreMonthRenderArr(renderDate); const currentMonthRenderArr = computeCurrenMonthRenderArr(renderDate); const nextMonthRenderArr = this.props.currentMonthOnly ? [] : computeNexMonthRenderArr(renderDate); start && (isStartMonth = dayjs(start).startOf('month').isSame(renderDateMonthStart)); end && (isEndMonth = dayjs(end).startOf('month').isSame(renderDateMonthStart)); this.setState({ preMonthRenderArr, currentMonthRenderArrPro: currentMonthRenderArr.map(item => this.computeRenderDatePro(item)), nextMonthRenderArr, isStartMonth, isEndMonth }); }; this.clickPreMonth = () => { const { start } = this.props; const { renderDate } = this.state; const preMonth = renderDate.subtract(1, 'month'); if (start && dayjs(start).isAfter(preMonth)) return; this.setState({ renderDate: preMonth }, this.renderNewMonth); }; this.clickNextMonth = () => { const { end } = this.props; const { renderDate } = this.state; const nextMonth = renderDate.add(1, 'month'); if (end && dayjs(end).isBefore(nextMonth)) return; this.setState({ renderDate: nextMonth }, this.renderNewMonth); }; this.clickItem = (date, isDisabled) => { if (isDisabled) return; const { format, onSelect } = this.props; const selectedDate = dayjs(date).format(format); onSelect && onSelect([selectedDate]); }; this.coumputeIsSelected = date => { const { selectedDate } = this.props; const _date = dayjs(date); return selectedDate.length === 1 ? _date.isSame(dayjs(selectedDate[0]), 'day') : _date.isBefore(dayjs(selectedDate[0]), 'day') && _date.isAfter(dayjs(selectedDate[1]), 'day'); }; this.computeRenderDatePro = renderDate => { const { format, onDateHooks, start, end } = this.props; const renderDatePro = new RenderDatePro(renderDate); const date = dayjs(renderDatePro.str); const dateStr = date.format(format); if (start && date.isBefore(dayjs(start)) || end && date.isAfter(dayjs(end))) { renderDatePro.note = ''; renderDatePro.disable = true; return renderDatePro; } // date hooks const setDisable = _disable => renderDatePro.disable = _disable; const setNote = _note => renderDatePro.note = _note; onDateHooks && onDateHooks(dateStr, { setDisable, setNote }); return renderDatePro; }; } componentDidMount() { const { currentDate } = this.props; if (currentDate) { this.setState({ renderDate: dayjs(currentDate) }, this.renderNewMonth); } else { this.renderNewMonth(); } } componentWillReceiveProps(nextProps) { const { currentDate, onDateHooks } = this.props; if (currentDate !== nextProps.currentDate || onDateHooks !== nextProps.onDateHooks) { this.setState({ renderDate: dayjs(nextProps.currentDate) }, this.renderNewMonth); } } render() { const { themColor, currentMonthOnly } = this.props; const { renderDate, isStartMonth, isEndMonth } = this.state; const renderYear = renderDate.year(); const renderMonth = renderDate.month() + 1; return <View className="xc-calendar"> <View className="xc-calendar__title"> <View className="xc-calendar__month-switch"> {!isStartMonth && <View className="xc-calendar__month-switch__button" style={`background-color: ${themColor}`} onClick={this.clickPreMonth}> <XcArrow degree={270} weight="2px" color="#fff" size="8px" /> </View>} </View> <View> {renderYear}年{renderMonth}月 </View> <View className="xc-calendar__month-switch"> {!isEndMonth && <View className="xc-calendar__month-switch__button" style={`background-color: ${themColor}`} onClick={this.clickNextMonth}> <XcArrow weight="2px" color="#fff" size="8px" /> </View>} </View> </View> <View className="xc-calendar__content"> <View className="xc-calendar__week"> <View className="xc-calendar__week__day">一</View> <View className="xc-calendar__week__day">二</View> <View className="xc-calendar__week__day">三</View> <View className="xc-calendar__week__day">四</View> <View className="xc-calendar__week__day">五</View> <View className="xc-calendar__week__day">六</View> <View className="xc-calendar__week__day">日</View> </View> <View className="xc-calendar__dates"> {this.state.preMonthRenderArr.map((date, index) => <View key={index} className="xc-calendar__date xc-calendar__date--other-month"> {currentMonthOnly ? '' : date.date} </View>)} {this.state.currentMonthRenderArrPro.map((date, index) => { const isSelected = this.coumputeIsSelected(date.str); const itemClass = classNames('xc-calendar__date', { 'xc-calendar__date--disable': date.disable, 'xc-calendar__date--selected': isSelected }); const itemStyle = { backgroundColor: themColor }; return <View key={index} className={itemClass} onClick={this.clickItem.bind(this, date.str, date.disable)}> <View> {date.date}</View> {date.note && <View className="xc-calendar__date__note">{date.note}</View>} {isSelected && <View className="xc-calendar__date__bg--selected" style={itemStyle} />} </View>; })} {this.state.nextMonthRenderArr.map((date, index) => <View key={index} className="xc-calendar__date xc-calendar__date--other-month"> {this.props.currentMonthOnly ? '' : date.date} </View>)} </View> </View> </View>; } } XcCalendar.defaultProps = { isMultiSelect: false, format: 'YYYY-MM-DD', currentMonthOnly: false, selectedDate: [] }; export default XcCalendar;