用react写一个日历插件

来源:互联网 发布:网络运营 编辑:程序博客网 时间:2024/05/12 12:00

说明

个人娱乐所写(不保证BUG不存在),UI方面参照其他人的UI设计

详情见本人github案例:案例

支持功能

  • 初始化日期
  • 高亮’今天’以及选择日期
  • 历史记录选择日期
  • 支持tag标识
  • 支持选择日期回调
  • 屏幕适应

效果图

这里写图片描述

这里写图片描述

基本思路

  1. 计算出这一年中的每个月对应的天数,其中需要根据年份来判断2月份到底是28天还是29天,使用数组保存
  2. 计算出这个月的第一天是星期几,来决定前面应该会有多少上个月的空格以及根据天数来判断月后应该有多少天来弥补
  3. 渲染思路:

    • 使用三个数组,分别存有上一个月、当前月以及下一个月应该渲染的天数
    • 数组合并,根据每一行应该显示7列的特性,将大数组划分为6个小数组,这6个小数组中即为每一行应该显示的星期数
  4. 具体代码

/** * Created by Ryn on 2016/8/7. * 日历组件 */import React from 'react';import H from '../helpers/H';const Calendar = React.createClass({    /**     * 默认的属性     */    getDefaultProps() {        return {            row_number : 6,            col_number : 7        }    },    /**     * 组件初始化状态     */    getInitialState() {        return {            current_year : H.getFullYear(),            current_month : H.getMonth(),            current_day : H.getDate(),            select_year : H.getFullYear(),            select_month : H.getMonth(),            select_day : H.getDate(),            history_year : undefined,            history_month : undefined,            history_day : undefined,            date_num_array : []        }    },    componentWillReceiveProps(nextProps) {        // todo    },    /**     * 组件渲染完后执行     */    componentDidMount() {        let { year, month, day} = this.props;        // 初始化状态        if(year && month && day) {            let date_num_array = this._initMonthDayNumber(year),                first_day = H.weekOfMonth(new Date(year, month - 1));            this.setState({                select_year : year,                select_month : month - 1,                select_day : day,                date_num_array : date_num_array,                first_day : first_day            });        }    },    /**     * 给月份数组附上每月天数     * @param year 年份     * @private     */    _initMonthDayNumber(year) {        let _date_array = [];        for (var i = 0; i < 12; i++) {            switch (i + 1) {                case 1:                case 3:                case 5:                case 7:                case 8:                case 10:                case 12:                    _date_array.push(31);                    break;                case 4:                case 6:                case 9:                case 11:                    _date_array.push(30);                    break;                case 2:                    if (H.isLeapYear(year)) {                        _date_array.push(29);                    } else {                        _date_array.push(28);                    }                    break;                default:                    break;            }        }        return _date_array;    },    /**     * 组件将要挂载     * 设置月份数组以及计算出每月的第一天星期几     */    componentWillMount() {        let date_num_array = this._initMonthDayNumber(this.state.current_year),            first_day = H.weekOfMonth();        this.setState({date_num_array : date_num_array, first_day : first_day});    },    /**     * 日期选择     * @param s_day     */    selectDate(s_day) {        let { select_year, select_month} = this.state;        this.setState({            history_year : select_year,            history_month : select_month,            history_day : s_day,            select_day : s_day        }, () => {            this.props.onSelectDate(select_year, select_month + 1, s_day);        });    },    /**     * 前一个月     */    previousMonth() {        let { current_year, current_month, current_day,            select_year, select_month, select_day, date_num_array, first_day} = this.state;        if (select_month === 0) {            select_year = +select_year - 1;            select_month = 11;            date_num_array = this._initMonthDayNumber(select_year);        } else {            select_month = +select_month - 1;        }        first_day = H.weekOfMonth(new Date(select_year, select_month));        if (current_year === select_year &&            current_month === select_month) {            select_day = current_day;        } else {            select_day = undefined;        }        this.setState({            select_year : select_year,            select_month : select_month,            select_day : select_day,            date_num_array : date_num_array,            first_day : first_day        })    },    /**     * 之后一个月     */    nextMonth() {        let { current_year, current_month, current_day,            select_year, select_month, select_day, date_num_array, first_day} = this.state;        if (select_month === 11) {            select_year = +select_year + 1;            select_month = 0;            date_num_array = this._initMonthDayNumber(select_year);        } else {            select_month = +select_month + 1;        }        first_day = H.weekOfMonth(new Date(select_year, select_month));        if (current_year === select_year &&            current_month === select_month) {            select_day = current_day;        } else {            select_day = undefined;        }        this.setState({            select_year : select_year,            select_month : select_month,            select_day : select_day,            date_num_array : date_num_array,            first_day : first_day        })    },    /**     * 渲染页面     * @returns {XML}     */    render() {        let { row_number, col_number, tags } = this.props;        let { current_year, current_month, current_day,            select_year, select_month, select_day,            history_year, history_month, history_day,            date_num_array, first_day} = this.state;        let month_day = date_num_array[select_month],            n_day = row_number * col_number - first_day - month_day,            previous_month_days = undefined,            previous_days = [],            current_days = [],            next_days = [],            total_days = [],            previous_month = undefined;        if (select_month === 0) {            previous_month = 11;        } else {            previous_month = select_month - 1;        }        previous_month_days = date_num_array[previous_month];        for (let i = 0; i < first_day; i++) {            let previous_link = (<li className="item-gray" key={'previous'+i}>                <a href="javascript:;">{previous_month_days - (first_day - i) + 1}</a>            </li>);            previous_days.push(previous_link);        }        let currentClassName = '',            currentText = '';        for (let i = 0; i < month_day; i++) {            // 今天样式            if (current_year == select_year && current_month == select_month && current_day == (i + 1)) {                currentClassName = 'item-current';                currentText = '今天';            } else {                currentText = i + 1;                // 判断选择样式与历史样式是否相等,相等激活                if (select_year == history_year && select_month == history_month && history_day == (i + 1)) {                    currentClassName = 'item-active';                } else {                    currentClassName = '';                }            }            // 添加tag样式            if (tags.length > 0) {                for (let j = 0; j < tags.length; j++) {                    if ((i + 1) === tags[j]) {                        currentClassName += 'item-tag';                        break;                    }                }            }            let current_link = (<li className={currentClassName} key={'current'+i}>                <a href="javascript:;" onClick={this.selectDate.bind(this, i + 1)}>                    {currentText}                </a>            </li>);            current_days.push(current_link);        }        for (let i = 0; i < n_day; i++) {            let next_link = (<li className="item-gray" key={'next'+i}>                <a href="javascript:;">{i + 1}</a>            </li>);            next_days.push(next_link);        }        total_days = previous_days.concat(current_days, next_days);        let ul_list = [];        if (total_days.length > 0) {            for (let i = 0; i < row_number; i++) {                let li_list = [],                    start_index = i * col_number,                    end_index = (i + 1) * col_number;                for (let j = start_index; j < end_index; j++) {                    li_list.push(total_days[j]);                }                ul_list.push(li_list);            }        }        return (            <div className="calendar">                <div className="calendar-header">                    <i className="icon-left" onClick={this.previousMonth}></i>                    <span>{select_year} 年 {select_month + 1} 月</span>                    <i className="icon-right" onClick={this.nextMonth}></i>                </div>                <div className="calendar-body">                    <ul className="c-body-head">                        <li></li>                        <li></li>                        <li></li>                        <li></li>                        <li></li>                        <li></li>                        <li></li>                    </ul>                    <div className="c-body-content">                        {                            ul_list.map((u, index) => {                                return (<ul key={'ul'+index} className="content-row">{u}</ul>);                            })                        }                    </div>                </div>            </div>        );    }});export default Calendar;

调用方式

import React from 'react';import ReactDOM from 'react-dom';import Calendar from './Calendar';const App = React.createClass({    render() {        return (            <Calendar onSelectDate={this.selectDate}                 year='2016'                 month='8'                 day='7'                 tags={[5, 22]} />        );    }});export default App;
0 0
原创粉丝点击