UNPKG

react-mobile-datepicker

Version:
1,235 lines (1,032 loc) 45.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react'), require('react-dom')) : typeof define === 'function' && define.amd ? define(['react', 'react-dom'], factory) : (global.reactMobileDatePicker = factory(global.React,global.ReactDOM)); }(this, (function (React,ReactDOM) { 'use strict'; function __$styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var React__default = 'default' in React ? React['default'] : React; ReactDOM = ReactDOM && ReactDOM.hasOwnProperty('default') ? ReactDOM['default'] : ReactDOM; __$styleInject(".datepicker-modal {\n position: absolute;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, .6);\n z-index: 999;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.datepicker {\n position: absolute;\n left: 0;\n bottom: 0;\n width: 100%;\n z-index: 1;\n font-size: 16px;\n text-align: center;\n font-family: arial,verdana,sans-serif;\n -webkit-box-sizing: content-box;\n box-sizing: content-box;\n -webkit-font-smoothing: antialiased;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.datepicker .datepicker-header {\n padding: 0 .5em;\n min-height: 2em;\n line-height: 2em;\n font-size: 1.125em;\n }\n\n.datepicker .datepicker-navbar {\n padding: 0 .5em .5em .5em;\n overflow: hidden;\n }\n\n.datepicker .datepicker-navbar-btn {\n height: 2.5em;\n line-height: 2.5em;\n float: right;\n padding: 0 1em;\n cursor: pointer;\n }\n\n.datepicker .datepicker-caption {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n padding: .5em .25em;\n }\n\n.datepicker .datepicker-caption-item {\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1;\n margin: 0 .25em;\n height: 40px;\n line-height: 40px;\n font-size: 1.2em;\n }\n\n.datepicker .datepicker-content {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n padding: .5em .25em;\n }\n\n.datepicker .datepicker-col-1 {\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1;\n margin: 0 .25em;\n }\n\n.datepicker .datepicker-viewport {\n height: 200px;\n position: relative;\n overflow: hidden\n }\n\n.datepicker .datepicker-viewport::after {\n content: '';\n position: absolute;\n z-index: 2;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n}\n\n.datepicker .datepicker-wheel {\n position: absolute;\n height: 40px;\n top: 50%;\n margin-top: -20px;\n width: 100%;\n }\n\n.datepicker .datepicker-scroll {\n list-style-type: none;\n padding: 0\n }\n\n.datepicker .datepicker-scroll>li {\n height: 40px;\n line-height: 40px;\n font-size: 1.375em;\n cursor: pointer;\n}\n\n.datepicker {\n\n /* default */\n}\n\n.datepicker.default {\n background-color: #f7f7f7;\n}\n\n.datepicker.default .datepicker-header {\n color: #4eccc4;\n}\n\n.datepicker.default .datepicker-wheel {\n border-top: 1px solid #4eccc4;\n border-bottom: 1px solid #4eccc4;\n}\n\n.datepicker.default .datepicker-caption-item {\n color: rgb(59, 59, 59);\n}\n\n.datepicker.default .datepicker-scroll li {\n color: rgb(59, 59, 59);\n }\n\n.datepicker.default .datepicker-scroll li.disabled {\n color: rgb(191, 191, 191);\n }\n\n.datepicker.default .datepicker-navbar-btn {\n color: #4eccc4;\n}\n\n.datepicker {\n\n /* dark */\n}\n\n.datepicker.dark {\n background-color: #263238;\n}\n\n.datepicker.dark .datepicker-header {\n color: #50ccc4;\n}\n\n.datepicker.dark .datepicker-wheel {\n border-top: 1px solid #50ccc4;\n border-bottom: 1px solid #50ccc4;\n}\n\n.datepicker.dark .datepicker-caption-item {\n color: rgb(201, 203, 204);\n}\n\n.datepicker.dark .datepicker-scroll li {\n color: rgb(201, 203, 204);\n }\n\n.datepicker.dark .datepicker-scroll li.disabled {\n color: rgb(87, 96, 100);\n }\n\n.datepicker.dark .datepicker-navbar-btn {\n color: #50ccc4;\n}\n\n.datepicker {\n\n /* ios */\n}\n\n.datepicker.ios {\n background-color: #f7f7f7;\n}\n\n.datepicker.ios .datepicker-col-1 {margin: 0;\n}\n\n.datepicker.ios .datepicker-header {\n color: rgb(59, 59, 59);\n padding: 0 3.5em;\n}\n\n.datepicker.ios .datepicker-viewport::after {\n background: -webkit-gradient(linear,left top, left bottom,from(#f7f7f7),color-stop(52%, rgba(245, 245, 245, 0)),color-stop(48%, rgba(245, 245, 245, 0)),to(#f7f7f7));\n background: linear-gradient(#f7f7f7,rgba(245, 245, 245, 0)52%,rgba(245, 245, 245, 0)48%,#f7f7f7);\n}\n\n.datepicker.ios .datepicker-wheel {\n border-top: 1px solid #dbdbdb;\n border-bottom: 1px solid #dbdbdb;\n}\n\n.datepicker.ios .datepicker-caption-item {\n color: rgb(59, 59, 59);\n}\n\n.datepicker.ios .datepicker-scroll li {\n color: rgb(59, 59, 59);\n }\n\n.datepicker.ios .datepicker-scroll li.disabled {\n color: rgb(191, 191, 191);\n }\n\n.datepicker.ios .datepicker-navbar {\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 100%;\n padding: 0;\n border-bottom: 1px solid #acacac;\n}\n\n.datepicker.ios .datepicker-navbar-btn {\n color: #007aff;\n}\n\n.datepicker.ios .datepicker-navbar-btn:nth-child(2) {\n float: left;\n}\n\n.datepicker.ios .datepicker-content {\n padding-top: 48px;\n}\n\n.datepicker.ios .datepicker-header + .datepicker-content {\n padding-top: 0;\n}\n\n.datepicker.ios .datepicker-caption + .datepicker-content {\n padding-top: 0;\n}\n\n.datepicker {\n\n /* android */\n}\n\n.datepicker.android, .datepicker.android-dark {\n background-color: #f5f5f5;\n}\n\n.datepicker.android .datepicker-header, .datepicker.android-dark .datepicker-header {\n color: #31b6e7;\n border-bottom: 2px solid #31b6e7;\n}\n\n.datepicker.android .datepicker-col-1, .datepicker.android-dark .datepicker-col-1 {margin: 0 .625em;\n}\n\n.datepicker.android .datepicker-viewport::after, .datepicker.android-dark .datepicker-viewport::after {\n background-image: -webkit-gradient(linear,left top, left bottom,from(#f5f5f5),color-stop(52%, rgba(245, 245, 245, 0)),color-stop(48%, rgba(245, 245, 245, 0)),to(#f5f5f5));\n background-image: linear-gradient(#f5f5f5,rgba(245, 245, 245, 0)52%,rgba(245, 245, 245, 0)48%,#f5f5f5);\n}\n\n.datepicker.android .datepicker-wheel, .datepicker.android-dark .datepicker-wheel {\n border-top: 2px solid #31b6e7;\n border-bottom: 2px solid #31b6e7;\n}\n\n.datepicker.android .datepicker-caption-item, .datepicker.android-dark .datepicker-caption-item {\n color: rgb(56, 56, 56);\n}\n\n.datepicker.android .datepicker-scroll li, .datepicker.android-dark .datepicker-scroll li {\n font-size: 1.125em;\n color: rgb(56, 56, 56);\n }\n\n.datepicker.android .datepicker-scroll li.disabled, .datepicker.android-dark .datepicker-scroll li.disabled {\n color: rgb(188, 188, 188);\n }\n\n.datepicker.android .datepicker-navbar, .datepicker.android-dark .datepicker-navbar {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n border-top: 1px solid #d9d4d4;\n padding: 0;\n}\n\n.datepicker.android .datepicker-navbar-btn, .datepicker.android-dark .datepicker-navbar-btn {\n padding: 0;\n color: #000;\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1;\n}\n\n.datepicker.android .datepicker-navbar-btn:nth-child(2), .datepicker.android-dark .datepicker-navbar-btn:nth-child(2) {\n border-left: 1px solid #d9d4d4;\n}\n\n.datepicker {\n\n /* android-dark */\n}\n\n.datepicker.android-dark {\n background-color: #292829;\n}\n\n.datepicker.android-dark .datepicker-viewport::after {\n background-image: -webkit-gradient(linear,left top, left bottom,from(#282828),color-stop(52%, rgba(40, 40, 40, 0)),color-stop(48%, rgba(40, 40, 40, 0)),to(#282828));\n background-image: linear-gradient(#282828,rgba(40, 40, 40, 0)52%,rgba(40, 40, 40, 0)48%,#282828);\n}\n\n.datepicker.android-dark .datepicker-caption-item {\n color: rgb(199, 199, 199);\n}\n\n.datepicker.android-dark .datepicker-scroll li {\n color: rgb(199, 199, 199);\n }\n\n.datepicker.android-dark .datepicker-scroll li.disabled {\n color: rgb(88, 88, 88);\n }\n\n.datepicker.android-dark .datepicker-navbar { border-color: #424542;\n}\n\n.datepicker.android-dark .datepicker-navbar-btn {\n color: #fff;\n}\n\n.datepicker.android-dark .datepicker-navbar-btn:nth-child(2) {\n border-color: #424542;\n}\n", {}); /** * @module time工具 */ function throwIfInvalidDate(date) { if (Object.prototype.toString.call(date, null) !== '[object Date]') { throw new Error('参数类型不对'); } } function daysInMonth(year, month) { return new Date(year, month + 1, 0).getDate(); } /** * 对Date的扩展,将 Date 转化为指定格式的String * @param {Date} 日期 * @return {String} 字符串格式 */ function convertDate(date, format) { var str = format; var o = { 'M+': date.getMonth() + 1, 'D+': date.getDate(), 'h+': date.getHours(), 'm+': date.getMinutes(), 's+': date.getSeconds() }; if (/(Y+)/.test(format)) { str = str.replace(RegExp.$1, date.getFullYear().toString().substr(4 - RegExp.$1.length)); } for (var k in o) { // eslint-disable-line if (new RegExp('(' + k + ')').test(format)) { str = str.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(o[k].toString().length)); } } return str; } /** * 获取相对日期的偏移日期 * @param {Date} 日期 * @return {number} 相对的天数 */ function nextYear(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var date = new Date(now.getFullYear() + index, now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds()); return date; } function nextMonth(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var year = now.getFullYear(); var month = now.getMonth() + index; var dayOfMonth = Math.min(now.getDate(), daysInMonth(year, month)); var date = new Date(year, month, dayOfMonth, now.getHours(), now.getMinutes(), now.getSeconds()); return date; } function nextDate(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var date = new Date(now.getTime() + index * 24 * 60 * 60 * 1000); return date; } function nextHour(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var date = new Date(now.getTime() + index * 60 * 60 * 1000); return date; } function nextMinute(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var date = new Date(now.getTime() + index * 60 * 1000); return date; } function nextSecond(now) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; throwIfInvalidDate(now); var date = new Date(now.getTime() + index * 1000); return date; } var TimeUtil = Object.freeze({ convertDate: convertDate, nextYear: nextYear, nextMonth: nextMonth, nextDate: nextDate, nextHour: nextHour, nextMinute: nextMinute, nextSecond: nextSecond }); function shallowEqual(prev, next) { if (prev === next) return true; var prevKeys = Object.keys(prev); var nextKeys = Object.keys(next); if (prevKeys.length !== nextKeys.length) return false; return prevKeys.every(function (key) { return prev.hasOwnProperty(key) && prev[key] === next[key]; }); } function PureRender(Component$$1) { Component$$1.prototype.shouldComponentUpdate = function (nextProps, nextState) { return PureRender.shouldComponentUpdate(nextProps, nextState, this.props, this.state); }; } PureRender.shouldComponentUpdate = function (nextProps, nextState, preProps, preState) { return !shallowEqual(preProps, nextProps) || !shallowEqual(preState, nextState); }; /** * 驼峰写法 * @param {String} str 要转化的字符串 * @return {String} 转化后的字符串 */ function camelCase(str) { return str.replace(/-([a-z])/g, function ($0, $1) { return $1.toUpperCase(); }).replace('-', ''); } /** * 格式化css属性对象 * @param {Object} props 属性对象 * @return {Object} 添加前缀的格式化属性对象 */ function formatCss(props) { var prefixs = ['-webkit-', '-moz-', '-ms-']; var result = {}; var regPrefix = /transform|transition/; for (var key in props) { if (props.hasOwnProperty(key)) { var styleValue = props[key]; // 如果检测是transform或transition属性 if (regPrefix.test(key)) { for (var i = 0; i < prefixs.length; i++) { var styleName = camelCase(prefixs[i] + key); result[styleName] = styleValue.replace(regPrefix, prefixs[i] + '$&'); } } result[key] = styleValue; } } return result; } /** * 为元素添加css样式 * @param {Object} element 目标元素 * @param {Object} props css属性对象 */ function addPrefixCss(element, props) { var formatedProps = formatCss(props); for (var key in formatedProps) { if (formatedProps.hasOwnProperty(key)) { element.style[key] = formatedProps[key]; } } } var asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function (fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function (value) { return new AwaitValue(value); } }; }(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var objectWithoutProperties = function (obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var toArray = function (arr) { return Array.isArray(arr) ? arr : Array.from(arr); }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; /** * @module Date组件 */ var DATE_HEIGHT = 40; // 每个日期的高度 var DATE_LENGTH = 10; // 日期的个数 var MIDDLE_INDEX = Math.floor(DATE_LENGTH / 2); // 日期数组中间值的索引 var MIDDLE_Y = -DATE_HEIGHT * MIDDLE_INDEX; // translateY值 var isUndefined = function isUndefined(val) { return typeof val === 'undefined'; }; var isFunction = function isFunction(val) { return Object.prototype.toString.apply(val) === '[object Function]'; }; /** * Class Date组件类 * @extends Component */ var DatePickerItem = function (_Component) { inherits(DatePickerItem, _Component); function DatePickerItem(props) { classCallCheck(this, DatePickerItem); var _this = possibleConstructorReturn(this, (DatePickerItem.__proto__ || Object.getPrototypeOf(DatePickerItem)).call(this, props)); _this.animating = false; // 判断是否在transition过渡动画之中 _this.touchY = 0; // 保存touchstart的pageY _this.translateY = 0; // 容器偏移的距离 _this.currentIndex = MIDDLE_INDEX; // 滑动中当前日期的索引 _this.moveDateCount = 0; // 一次滑动移动了多少个时间 _this.state = { translateY: MIDDLE_Y, marginTop: (_this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }; _this.renderDatepickerItem = _this.renderDatepickerItem.bind(_this); _this.handleContentTouch = _this.handleContentTouch.bind(_this); _this.handleContentMouseDown = _this.handleContentMouseDown.bind(_this); _this.handleContentMouseMove = _this.handleContentMouseMove.bind(_this); _this.handleContentMouseUp = _this.handleContentMouseUp.bind(_this); return _this; } createClass(DatePickerItem, [{ key: 'componentWillMount', value: function componentWillMount() { this._iniDates(this.props.value); } }, { key: 'componentDidMount', value: function componentDidMount() { var viewport = this.viewport; viewport.addEventListener('touchstart', this.handleContentTouch, false); viewport.addEventListener('touchmove', this.handleContentTouch, false); viewport.addEventListener('touchend', this.handleContentTouch, false); viewport.addEventListener('mousedown', this.handleContentMouseDown, false); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.value.getTime() === this.props.value.getTime()) { return; } this._iniDates(nextProps.value); this.currentIndex = MIDDLE_INDEX; this.setState({ translateY: MIDDLE_Y, marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } /** * Optimization component, Prevents unnecessary rendering * Only value or state change should re-rendering * * @param {Object} nextProps next props * @param {Object} nextState next state * @return {Boolean} Whether re-rendering */ }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { return nextProps.value.getTime() !== this.props.value.getTime() || !shallowEqual(nextState, this.state); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { var viewport = this.viewport; viewport.removeEventListener('touchstart', this.handleContentTouch, false); viewport.removeEventListener('touchmove', this.handleContentTouch, false); viewport.removeEventListener('touchend', this.handleContentTouch, false); viewport.removeEventListener('mousedown', this.handleContentMouseDown, false); } }, { key: '_iniDates', value: function _iniDates(date) { var _this2 = this; var typeName = this.props.type; var dates = Array.apply(undefined, toConsumableArray(Array(DATE_LENGTH))).map(function (value, index) { return TimeUtil['next' + typeName](date, (index - MIDDLE_INDEX) * _this2.props.step); }); this.setState({ dates: dates }); } }, { key: '_updateDates', value: function _updateDates(direction) { var typeName = this.props.type; var dates = this.state.dates; if (direction === 1) { this.currentIndex++; this.setState({ dates: [].concat(toConsumableArray(dates.slice(1)), [TimeUtil['next' + typeName](dates[dates.length - 1], this.props.step)]), marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } else { this.currentIndex--; this.setState({ dates: [TimeUtil['next' + typeName](dates[0], -this.props.step)].concat(toConsumableArray(dates.slice(0, dates.length - 1))), marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } } }, { key: '_checkIsUpdateDates', value: function _checkIsUpdateDates(direction, translateY) { return direction === 1 ? this.currentIndex * DATE_HEIGHT + DATE_HEIGHT / 2 < -translateY : this.currentIndex * DATE_HEIGHT - DATE_HEIGHT / 2 > -translateY; } /** * 清除对象的transition样式 * @param {Dom} obj 指定的对象 * @return {undefined} */ }, { key: '_clearTransition', value: function _clearTransition(obj) { addPrefixCss(obj, { transition: '' }); } /** * 滑动到下一日期 * @param {number} direction 滑动方向 * @return {undefined} */ }, { key: '_moveToNext', value: function _moveToNext(direction) { var date = this.state.dates[MIDDLE_INDEX]; var _props = this.props, max = _props.max, min = _props.min; if (direction === -1 && date.getTime() < min.getTime() && this.moveDateCount) { this._updateDates(1); } else if (direction === 1 && date.getTime() > max.getTime() && this.moveDateCount) { this._updateDates(-1); } this._moveTo(this.refs.scroll, this.currentIndex); } /** * 添加滑动动画 * @param {DOM} obj DOM对象 * @param {number} angle 角度 * @return {undefined} */ }, { key: '_moveTo', value: function _moveTo(obj, currentIndex) { var _this3 = this; this.animating = true; addPrefixCss(obj, { transition: 'transform .2s ease-out' }); this.setState({ translateY: -currentIndex * DATE_HEIGHT }); // NOTE: There is no transitionend, setTimeout is used instead. setTimeout(function () { _this3.animating = false; _this3.props.onSelect(_this3.state.dates[MIDDLE_INDEX]); _this3._clearTransition(_this3.refs.scroll); }, 200); } }, { key: 'handleStart', value: function handleStart(event) { this.touchY = !isUndefined(event.targetTouches) && !isUndefined(event.targetTouches[0]) ? event.targetTouches[0].pageY : event.pageY; this.translateY = this.state.translateY; this.moveDateCount = 0; } }, { key: 'handleMove', value: function handleMove(event) { var touchY = !isUndefined(event.targetTouches) && !isUndefined(event.targetTouches[0]) ? event.targetTouches[0].pageY : event.pageY; var dir = touchY - this.touchY; var translateY = this.translateY + dir; var direction = dir > 0 ? -1 : 1; // 日期最小值,最大值限制 var date = this.state.dates[MIDDLE_INDEX]; var _props2 = this.props, max = _props2.max, min = _props2.min; if (date.getTime() < min.getTime() || date.getTime() > max.getTime()) { return; } // 检测是否更新日期列表 if (this._checkIsUpdateDates(direction, translateY)) { this.moveDateCount = direction > 0 ? this.moveDateCount + 1 : this.moveDateCount - 1; this._updateDates(direction); } this.setState({ translateY: translateY }); } }, { key: 'handleEnd', value: function handleEnd(event) { var touchY = event.pageY || event.changedTouches[0].pageY; var dir = touchY - this.touchY; var direction = dir > 0 ? -1 : 1; this._moveToNext(direction); } /** * 滑动日期选择器触屏事件 * @param {Object} event 事件对象 * @return {undefined} */ }, { key: 'handleContentTouch', value: function handleContentTouch(event) { event.preventDefault(); if (this.animating) return; if (event.type === 'touchstart') { this.handleStart(event); } else if (event.type === 'touchmove') { this.handleMove(event); } else if (event.type === 'touchend') { this.handleEnd(event); } } /** * 滑动日期选择器鼠标事件 * @param {Object} event 事件对象 * @return {undefined} */ }, { key: 'handleContentMouseDown', value: function handleContentMouseDown(event) { if (this.animating) return; this.handleStart(event); document.addEventListener('mousemove', this.handleContentMouseMove); document.addEventListener('mouseup', this.handleContentMouseUp); } }, { key: 'handleContentMouseMove', value: function handleContentMouseMove(event) { if (this.animating) return; this.handleMove(event); } }, { key: 'handleContentMouseUp', value: function handleContentMouseUp(event) { if (this.animating) return; this.handleEnd(event); document.removeEventListener('mousemove', this.handleContentMouseMove); document.removeEventListener('mouseup', this.handleContentMouseUp); } /** * 渲染一个日期DOM对象 * @param {Object} date date数据 * @return {Object} JSX对象 */ }, { key: 'renderDatepickerItem', value: function renderDatepickerItem(date, index) { var className = date < this.props.min || date > this.props.max ? 'disabled' : ''; var formatDate = void 0; if (isFunction(this.props.format)) { formatDate = this.props.format(date); } else { formatDate = convertDate(date, this.props.format); } return React__default.createElement( 'li', { key: index, className: className }, formatDate ); } }, { key: 'render', value: function render() { var _this4 = this; var scrollStyle = formatCss({ transform: 'translateY(' + this.state.translateY + 'px)', marginTop: this.state.marginTop }); return React__default.createElement( 'div', { className: 'datepicker-col-1' }, React__default.createElement( 'div', { ref: function ref(viewport) { return _this4.viewport = viewport; } // eslint-disable-line , className: 'datepicker-viewport' }, React__default.createElement( 'div', { className: 'datepicker-wheel' }, React__default.createElement( 'ul', { ref: 'scroll', className: 'datepicker-scroll', style: scrollStyle }, this.state.dates.map(this.renderDatepickerItem) ) ) ) ); } }]); return DatePickerItem; }(React.Component); /** * 默认属性 */ var defaultProps = { isPopup: true, isOpen: false, theme: 'default', value: new Date(), min: new Date(1970, 0, 1), max: new Date(2050, 0, 1), showFooter: true, showHeader: true, showCaption: false, dateConfig: { 'year': { format: 'YYYY', caption: 'Year', step: 1 }, 'month': { format: 'M', caption: 'Mon', step: 1 }, 'date': { format: 'D', caption: 'Day', step: 1 } }, headerFormat: 'YYYY/MM/DD', confirmText: '完成', cancelText: '取消', onChange: function onChange() {}, onSelect: function onSelect() {}, onCancel: function onCancel() {} }; /** * 日期配置 */ var dateConfigMap = { 'year': { format: 'YYYY', caption: 'Year', step: 1 }, 'month': { format: 'M', caption: 'Mon', step: 1 }, 'date': { format: 'D', caption: 'Day', step: 1 }, 'hour': { format: 'hh', caption: 'Hour', step: 1 }, 'minute': { format: 'mm', caption: 'Min', step: 1 }, 'second': { format: 'hh', caption: 'Sec', step: 1 } }; /** * @module DatePicker Component */ /** * 大写首字母 * @param {String} 字符串 */ var capitalize = function capitalize(_ref) { var _ref2 = toArray(_ref), first = _ref2[0], rest = _ref2.slice(1); return first.toUpperCase() + rest.join(''); }; /** * 判断数组 * @param {any} val */ var isArray = function isArray(val) { return Object.prototype.toString.apply(val) === '[object Array]'; }; /** * Class DatePicker Component Class * @extends Component */ var DatePicker = function (_Component) { inherits(DatePicker, _Component); function DatePicker(props) { classCallCheck(this, DatePicker); var _this = possibleConstructorReturn(this, (DatePicker.__proto__ || Object.getPrototypeOf(DatePicker)).call(this, props)); _this.state = { value: nextDate(_this.props.value) }; if ('dateFormat' in props) { console.warn('dateFormat已经被弃用, 请使用dateConfig属性配置'); } if ('dateSteps' in props) { console.warn('dateSteps已经被弃用, 请使用dateConfig属性配置'); } if ('showFormat' in props) { console.warn('headerFormat, 请使用dateConfig属性'); } _this.handleFinishBtnClick = _this.handleFinishBtnClick.bind(_this); _this.handleDateSelect = _this.handleDateSelect.bind(_this); return _this; } createClass(DatePicker, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { // update value of state var date = nextDate(nextProps.value); if (date.getTime() !== this.state.value.getTime()) { this.setState({ value: date }); } } /** * When you swipe two datepickeritems at the same time. * Prevent dates from going out. */ }, { key: 'componentDidUpdate', value: function componentDidUpdate() { var value = this.state.value; var _props = this.props, min = _props.min, max = _props.max; if (value.getTime() > max.getTime()) { this.setState({ value: max }); } if (value.getTime() < min.getTime()) { this.setState({ value: min }); } } /** * Optimization component, Prevents unnecessary rendering * Only props or state change or value before re-rendering * * @param {Object} nextProps next props * @param {Object} nextState next state * @return {Boolean} Whether re-rendering */ }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { var date = nextDate(nextState.value); return date.getTime() !== this.state.value.getTime() || PureRender.shouldComponentUpdate(nextProps, nextState, this.props, this.state); } /** * 点击完成按钮事件 * @return {undefined} */ }, { key: 'handleFinishBtnClick', value: function handleFinishBtnClick() { this.props.onSelect(this.state.value); } /** * 选择下一个日期 * @return {undefined} */ }, { key: 'handleDateSelect', value: function handleDateSelect(value) { var _this2 = this; this.setState({ value: value }, function () { _this2.props.onChange(value); }); } /** * 格式化dateConfig * @param {*} dataConfig dateConfig属性 */ }, { key: 'normalizeDateConfig', value: function normalizeDateConfig(dataConfig) { var configList = []; if (isArray(dataConfig)) { for (var i = 0; i < dataConfig.length; i++) { var _value = dataConfig[i]; if (typeof _value === 'string') { var lowerCaseKey = _value.toLocaleLowerCase(); configList.push(_extends({}, dateConfigMap[lowerCaseKey], { type: capitalize(lowerCaseKey) })); } } } else { for (var key in dataConfig) { if (dataConfig.hasOwnProperty(key)) { var _lowerCaseKey = key.toLocaleLowerCase(); if (dateConfigMap.hasOwnProperty(_lowerCaseKey)) { configList.push(_extends({}, dateConfigMap[_lowerCaseKey], dataConfig[key], { type: capitalize(_lowerCaseKey) })); } } } } return configList; } /** * render函数 * @return {Object} JSX对象 */ }, { key: 'render', value: function render() { var _this3 = this; var _props2 = this.props, min = _props2.min, max = _props2.max, theme = _props2.theme, dateConfig = _props2.dateConfig, confirmText = _props2.confirmText, cancelText = _props2.cancelText, headerFormat = _props2.headerFormat, showHeader = _props2.showHeader, showFooter = _props2.showFooter, customHeader = _props2.customHeader, showCaption = _props2.showCaption; var value = this.state.value; var themeClassName = ['default', 'dark', 'ios', 'android', 'android-dark'].indexOf(theme) === -1 ? 'default' : theme; var dataConfigList = this.normalizeDateConfig(dateConfig); return React__default.createElement( 'div', { className: 'datepicker ' + themeClassName }, showHeader && React__default.createElement( 'div', { className: 'datepicker-header' }, customHeader || convertDate(value, headerFormat) ), showCaption && React__default.createElement( 'div', { className: 'datepicker-caption' }, dataConfigList.map(function (item, index) { return React__default.createElement( 'div', { key: index, className: 'datepicker-caption-item' }, item.caption ); }) ), React__default.createElement( 'div', { className: 'datepicker-content' }, dataConfigList.map(function (item, index) { return React__default.createElement(DatePickerItem, { key: index, value: value, min: min, max: max, step: item.step, type: item.type, format: item.format, onSelect: _this3.handleDateSelect }); }) ), showFooter && React__default.createElement( 'div', { className: 'datepicker-navbar' }, React__default.createElement( 'a', { className: 'datepicker-navbar-btn', onClick: this.handleFinishBtnClick }, confirmText ), React__default.createElement( 'a', { className: 'datepicker-navbar-btn', onClick: this.props.onCancel }, cancelText ) ) ); } }]); return DatePicker; }(React.Component); var renderSubtreeIntoContainer = ReactDOM.unstable_renderSubtreeIntoContainer; var Modal = function (_Component) { inherits(Modal, _Component); function Modal() { classCallCheck(this, Modal); return possibleConstructorReturn(this, (Modal.__proto__ || Object.getPrototypeOf(Modal)).apply(this, arguments)); } createClass(Modal, [{ key: 'componentDidMount', value: function componentDidMount() { this._div = document.createElement('div'); this._div.classList.add('Modal-Portal'); document.body.appendChild(this._div); this.renderPortal(this.props); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(newProps) { this.renderPortal(newProps); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { ReactDOM.unmountComponentAtNode(this._div); this._div.parentNode.removeChild(this._div); } }, { key: 'renderPortal', value: function renderPortal(props) { var portal = React__default.cloneElement(this.props.children, _extends({}, props, { key: 'portal' }), null); this.portal = renderSubtreeIntoContainer(this, portal, this._div); } }, { key: 'render', value: function render() { return React__default.createElement('noscript', null); } }]); return Modal; }(React.Component); Modal.defaultProps = { isOpen: false }; function EnhanceDatePicker(_ref) { var isOpen = _ref.isOpen, props = objectWithoutProperties(_ref, ['isOpen']); function onModalClose(event) { if (event.target === event.currentTarget) { props.onCancel(); } } return React__default.createElement( 'div', { style: { display: isOpen ? '' : 'none' }, onClick: onModalClose, className: 'datepicker-modal' }, React__default.createElement(DatePicker, props) ); } function ModalDatePicker(_ref2) { var isPopup = _ref2.isPopup, props = objectWithoutProperties(_ref2, ['isPopup']); if (!isPopup) { return React__default.createElement(DatePicker, props); } return React__default.createElement( Modal, props, React__default.createElement(EnhanceDatePicker, null) ); } ModalDatePicker.displayName = 'MobileDatePicker'; ModalDatePicker.defaultProps = defaultProps; return ModalDatePicker; }))); //# sourceMappingURL=react-mobile-datepicker.js.map