用react写一个日历插件
来源:互联网 发布:网络运营 编辑:程序博客网 时间:2024/05/12 12:00
说明
个人娱乐所写(不保证BUG不存在),UI方面参照其他人的UI设计
详情见本人github案例:案例
支持功能
- 初始化日期
- 高亮’今天’以及选择日期
- 历史记录选择日期
- 支持tag标识
- 支持选择日期回调
- 屏幕适应
效果图
基本思路
- 计算出这一年中的每个月对应的天数,其中需要根据年份来判断2月份到底是28天还是29天,使用数组保存
- 计算出这个月的第一天是星期几,来决定前面应该会有多少上个月的空格以及根据天数来判断月后应该有多少天来弥补
渲染思路:
- 使用三个数组,分别存有上一个月、当前月以及下一个月应该渲染的天数
- 数组合并,根据每一行应该显示7列的特性,将大数组划分为6个小数组,这6个小数组中即为每一行应该显示的星期数
具体代码
/** * 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
- 用react写一个日历插件
- 用JS写一个日历
- 用LUA写一个日历
- 从零开始写一个jquery日历插件(一)
- 从零开始写一个jquery日历插件(二)
- 用JS写的一个日历
- 随便写一个日历
- 4.19 javascript写一个日历(用表格写)
- 如何自己写一个日历
- 写一个Android日历控件
- wpf写的一个日历
- 急求一个用C#写的日历!
- 自己写的一个用函数实现的日历
- 用C++写一个日历程序,要求输入年份,显示全年的日历
- 用C++写一个日历程序,要求输入年份,显示全年的日历
- 徒手写一个java日历程序
- 写了一个个人桌面日历
- java写的一个日历行程
- saltstack配置管理
- python学习之一: python简介
- POJ 2115 C Looooops (扩展欧几里得算法)
- spring mvc 请求转发和重定向
- 156.Examine the following steps performed on a database instance: 1: The DBA grants the CREATE TABL
- 用react写一个日历插件
- 【PAT】(乙级)1011. A+B和C (15)
- gRPC请求中对header进行处理
- XML是什么
- 求最大子列合——最优算法(在线处理)
- java String类常用操作
- ARM指令集总结
- python有关时间的处理
- JavaScript引用类型——Date类型