Автор оригинала: Chris Harrington.
Я недавно был довольно большим поклонником реагирования JS и создавал большинство моих более новых проектов, используя его в сочетании с меньшим количеством и усердом (оба из которых потрясающие, хотя я слышал, что первое немного из моды в лимене SCSS в эти дни). Сегодня я буду писать о том, как создать артиллерию даты, используя реагирование. Я сделал Источник Доступно и даже опубликовано пакет Bower ( A-React DatePicker ) В случае, если вы хотите использовать его в своем причудливом проекте New Rection.
Я бы не назвал это нигде возле добычи, хотя, так что будет предупреждено! Для тех из вас, кто просто хочет увидеть сборник свидания в действии, я собрал Упрощенная демонстрационная страница это показывает, что вы получаете. Во всяком случае, на шоу!
План
Вот поломка каждого из классов, которые я буду пользоваться, и что они предназначены для достижения.
- DatePicker – содержащий класс. Он несет ответственность за поддержание государства, касающегося сборщика даты в целом, а также создание как на триггерах, так и с плавающим календарем.
- Календарь – Класс, используемый для визуализации плавающей панели, содержащий все, что пользователь взаимодействует с внешней стороны триггера.
- MESSHELDER – заголовок, детализируя текущий месяц внутри Календарь класс. Он также содержит левые и правые стрелки, используемые для разрешения пользователя навигации между месяцами.
- Weekheader – простой класс для отображения пользователей список дней через неделю.
- Недели – Класс, используемый для содержения каждого из рядов дней, которые пользователь выберет.
- Неделя – представляет собой ряд дней. Пользователь сможет выбрать один из этих дней. Различные изменения стиля в эти дни указывают на разные состояния: выбранные, сегодня, отключены и т. Д.
Примечание: Я не буду охватывать большую часть CSS в этой статье, так как выходит за рамки того, что я хочу придать. Если вы заинтересованы в том, какие стили используются, не стесняйтесь взглянуть на Демострационная страница или источник .
DatePicker
var DatePicker = React.createClass({ getInitialState: function() { var def = this.props.selected || new Date(); return { view: DateUtilities.clone(def), selected: DateUtilities.clone(def), minDate: null, maxDate: null, visible: false }; }, componentDidMount: function() { document.addEventListener("click", function(e) { if (this.state.visible && e.target.className !== "date-picker-trigger" && !this.parentsHaveClassName(e.target, "date-picker")) this.hide(); }.bind(this)); }, parentsHaveClassName: function(element, className) { var parent = element; while (parent) { if (parent.className && parent.className.indexOf(className) > -1) return true; parent = parent.parentNode; } }, setMinDate: function(date) { this.setState({ minDate: date }); }, setMaxDate: function(date) { this.setState({ maxDate: date }); }, onSelect: function(day) { this.setState({ selected: day }); this.props.onSelect(day); this.hide(); }, show: function() { this.setState({ visible: true }); }, hide: function() { this.setState({ visible: false }); }, render: function() { return React.createElement("div", {className: "ardp-date-picker"}, React.createElement("input", {type: "text", className: "date-picker-trigger", readOnly: true, value: DateUtilities.toString(this.state.selected), onClick: this.show}), React.createElement(Calendar, {visible: this.state.visible, view: this.state.view, selected: this.state.selected, onSelect: this.onSelect, minDate: this.state.minDate, maxDate: this.state.maxDate}) ); } });
Во-первых, Получающийся стадь
Функция определяет несколько примечательных вещей: Вид
и выбран
Свойства, прежняя из которых используется для определения того, какой месяц пользователь просмотра, когда последний является выбранным днем. Помащение
и Maxdate
Свойства используются для блокировки пользователя от выбора дат до или после указанных значений соответственно.
Когда DatePicker Монтирует, мы слушаем, когда пользователь нажимает в любом месте документа, чтобы скрыть Календарь если необходимо. Я проверяю названия классов элемента нажатия и рекурсивно проверяйте родительские элементы, чтобы убедиться, что я не закрываю его преждевременно.
SetMindate
и setmaxdate
Методы используются только для того, что: установка границ для выбираемого диапазона дата. Показать
и Скрыть
Методы довольно объяснительные, и установите Видимый
Государственная собственность к истинному и ложному, соответственно.
оказывать
Метод отвечает за запись двух вещей: во-первых, триггер для Календарь (входное поле только для чтения, в данном случае) и Календарь класс.
Календарь
var Calendar = React.createClass({ onMove: function(view, isForward) { this.refs.weeks.moveTo(view, isForward); }, onTransitionEnd: function() { this.refs.monthHeader.enable(); }, render: function() { return React.createElement("div", {className: "calendar" + (this.props.visible ? " visible" : "")}, React.createElement(MonthHeader, {ref: "monthHeader", view: this.props.view, onMove: this.onMove}), React.createElement(WeekHeader, null), React.createElement(Weeks, {ref: "weeks", view: this.props.view, selected: this.props.selected, onTransitionEnd: this.onTransitionEnd, onSelect: this.props.onSelect, minDate: this.props.minDate, maxDate: this.props.maxDate}) ); } });
Основная ответственность Календарь Класс – обеспечить абсолютно расположенную холст, с помощью которого пользователь может взаимодействовать. Это делает MESSHELDER , Weekheader и Недели классы. Это также дает прогулку, чтобы связать предыдущие/следующие месяцы событий в MESSHELDER Класс для обновлений состояния в Недели класс. Ontransitionend
Метод уволен после окончания перехода между месяцами, указывающие на то, что предыдущие/в следующие месячные кнопки в MESSHELDER Класс должен стать повторно включенным.
Заголовок месяца
var MonthHeader = React.createClass({ getInitialState: function() { return { view: DateUtilities.clone(this.props.view), enabled: true }; }, moveBackward: function() { var view = DateUtilities.clone(this.state.view); view.setMonth(view.getMonth()-1); this.move(view, false); }, moveForward: function() { var view = DateUtilities.clone(this.state.view); view.setMonth(view.getMonth()+1); this.move(view, true); }, move: function(view, isForward) { if (!this.state.enabled) return; this.setState({ view: view, enabled: false }); this.props.onMove(view, isForward); }, enable: function() { this.setState({ enabled: true }); }, render: function() { var enabled = this.state.enabled; return React.createElement("div", {className: "month-header"}, React.createElement("i", {className: (enabled ? "" : " disabled"), onClick: this.moveBackward}, String.fromCharCode(9664)), React.createElement("span", null, DateUtilities.toMonthAndYearString(this.state.view)), React.createElement("i", {className: (enabled ? "" : " disabled"), onClick: this.moveForward}, String.fromCharCode(9654)) ); } });
MESSHELDER Класс несет ответственность за две вещи: информирование пользователя в каком месяце они в настоящее время просматривают и меняют месяц, используя стрелки предыдущего и в следующем месяце слева и справа. Состояние содержит в настоящее время просматриваемый месяц (из которого происходит метка месяца/года) и включенный флаг, который устанавливается на FALSE, чтобы сделать кнопки предыдущего и в следующем месяце не отвечали. Это полезно для предотвращения пролета пользователю через несколько месяцев быстрее, чем эффекты перехода.
Бездельник
var WeekHeader = React.createClass({ render: function() { return React.createElement("div", {className: "week-header"}, React.createElement("span", null, "Sun"), React.createElement("span", null, "Mon"), React.createElement("span", null, "Tue"), React.createElement("span", null, "Wed"), React.createElement("span", null, "Thu"), React.createElement("span", null, "Fri"), React.createElement("span", null, "Sat") ); } });
Самый простой из классов, которые я излагаю, Weekheader Класс отвечает за только одну вещь: показывая пользователю список сокращенных дней в верхней части рядов дней. Там буквально больше ничего не сказать об этом классе.
Недели
var Weeks = React.createClass({ getInitialState: function() { return { view: DateUtilities.clone(this.props.view), other: DateUtilities.clone(this.props.view), sliding: null }; }, componentDidMount: function() { this.refs.current.getDOMNode().addEventListener("transitionend", this.onTransitionEnd); }, onTransitionEnd: function() { this.setState({ sliding: null, view: DateUtilities.clone(this.state.other) }); this.props.onTransitionEnd(); }, getWeekStartDates: function(view) { view.setDate(1); view = DateUtilities.moveToDayOfWeek(DateUtilities.clone(view), 0); var current = DateUtilities.clone(view); current.setDate(current.getDate()+7); var starts = [view], month = current.getMonth(); while (current.getMonth() === month) { starts.push(DateUtilities.clone(current)); current.setDate(current.getDate()+7); } return starts; }, moveTo: function(view, isForward) { this.setState({ sliding: isForward ? "left" : "right", other: DateUtilities.clone(view) }); }, render: function() { return React.createElement("div", {className: "weeks"}, React.createElement("div", {ref: "current", className: "current" + (this.state.sliding ? (" sliding " + this.state.sliding) : "")}, this.renderWeeks(this.state.view) ), React.createElement("div", {ref: "other", className: "other" + (this.state.sliding ? (" sliding " + this.state.sliding) : "")}, this.renderWeeks(this.state.other) ) ); }, renderWeeks: function(view) { var starts = this.getWeekStartDates(view), month = starts[1].getMonth(); return starts.map(function(s, i) { return React.createElement(Week, {key: i, start: s, month: month, selected: this.props.selected, onSelect: this.props.onSelect, minDate: this.props.minDate, maxDate: this.props.maxDate}); }.bind(this)); } });
Недели класс обертывает подходящее количество Неделя Ученые экземпляры в зависимости от месяца, который рассчитывается в getweekstartdates
функция. Когда компонент крепится, мы подключаемся к Переход на
Событие обертки недели, которое является тем, что движется, когда пользователь инициирует действие предыдущего или в следующем месяце. Для достижения анимации у нас есть два набора недель: первый («текущий»), который в настоящее время рассматривается пользователем, а последнее («другое»), которое находится в состоянии экрана. Когда пользователь нажимает на следующий месяц действий, MESSHELDER класс пожарит onmove
поддержка функции до Календарь класс, который в свою очередь информирует Недели Класс, который был уволен в следующем месяце. Скрытый список дней обновляется до подходящего месяца, то он и текущий вид скольжения влево. После того, как переход заканчивается, текущий вид (который сейчас выключен на экран слева), обновляется с выбранным месяцем и защелкивается на месте, анимация SANS, а также сбрасывается процесс.
var Week = React.createClass({ buildDays: function(start) { var days = [DateUtilities.clone(start)], clone = DateUtilities.clone(start); for (var i = 1; i <= 6; i++) { clone = DateUtilities.clone(clone); clone.setDate(clone.getDate()+1); days.push(clone); } return days; }, isOtherMonth: function(day) { return this.props.month !== day.month(); }, getDayClassName: function(day) { var className = "day"; if (DateUtilities.isSameDay(day, new Date())) className += " today"; if (this.props.month !== day.getMonth()) className += " other-month"; if (this.props.selected && DateUtilities.isSameDay(day, this.props.selected)) className += " selected"; if (this.isDisabled(day)) className += " disabled"; return className; }, onSelect: function(day) { if (!this.isDisabled(day)) this.props.onSelect(day); }, isDisabled: function(day) { var minDate = this.props.minDate, maxDate = this.props.maxDate; return (minDate && DateUtilities.isBefore(day, minDate)) || (maxDate && DateUtilities.isAfter(day, maxDate)); }, render: function() { var days = this.buildDays(this.props.start); return React.createElement("div", {className: "week"}, days.map(function(day, i) { return React.createElement("div", {key: i, onClick: this.onSelect.bind(null, day), className: this.getDayClassName(day)}, DateUtilities.toDayOfMonthString(day)) }.bind(this)) ); } });
Последний класс, Неделя несет ответственность за оказание списка дней с использованием Начать
пропры Builddays
Функция фокусируется на создании списка семи дней на неделю. оказывать
Способ передавать этот список, пишет div для представления каждый день, уверена, что применить правильный класс CSS для дня в день, как указано в ДняхклассНам
метод. Этот DIV также имеет обработчик кликов, чтобы позволить пользователю выбрать день. onselect
опора распространяется на DatePicker Класс, который содержит выбранный день.
Заключение
Этот сборщик даты не должен использоваться в качестве инструмента готовности к производству любым растяжением воображения, и в основном здесь будет служить учебником с целью преподавания о реагированных JS. Тем не менее, я сделал это доступен в пакете Bower, если вы хотели бы дать ему выстрел в вашем приложении.
bower install a-react-datepicker --save
Как я уже упоминал выше, если вы хотели бы взглянуть на действительно простое демо, посмотрите Отказ Источник также доступен.
Если у вас есть какие-либо вопросы, комментарий ниже. Спасибо за прочтение!