Моя работа часто требует добавления даты ввода в формы. Поскольку они еще не поддерживаются всеми браузерами, я всегда ищу лучший способ интегрировать их в свои страницы.
Вы можете увидеть последние данные о поддержке браузером для ввода даты на я могу использовать .
В дополнение к основному полю date-input
существуют и другие типы полей, связанные со временем:
- Поля
datetime
позволяют вводить даты и время в формате UTC . -
datetime-local
представляет дату и время без часового пояса -
time
-
month
представляет месяц и год -
week
представляет номер недели и год
Я создал тестовую страницу для всех перечисленных выше типов ввода даты с помощью Modernizr , и я протестировал ее во многих современных мобильных и настольных браузерах, использующих Browserstack . Например, это страница результатов при просмотре в Chrome (красные поля не поддерживаются):
Вы можете проверить это прямо в демоверсии здесь:
Этот тест приносит нам следующую информацию:
- Ни один браузер не поддерживает
datetime
вводаdatetime
. - Браузеры, которые поддерживают
datetime-local
также поддерживаютtime
иmonth
, в то время как типweek
не так хорошо поддерживается. - Все браузеры, кажется, игнорируют атрибут
lang
. То есть виджеты ввода браузера всегда используют системные настройки для формата даты и времени, поэтому невозможно отобразить виджет ввода с языком, отличным от родного.
Теперь мы знаем, что мы должны обрабатывать не только date
или date
/ время, но и формат даты (если нам нужно, чтобы она отличалась от системных настроек пользователя) и проблемы UTC / local. Кроме того, мы должны принять во внимание разницу между отображаемым форматом и возвращаемым при отправке формы.
Выбор резервного сценария
Существует множество JavaScript-решений для улучшения поддержки ввода данных во всех браузерах, и, конечно, у каждого из них есть свои плюсы и минусы. Мой самый последний проект был проектом на основе Bootstrap, поэтому я сначала искал сценарии, основанные на этой платформе. Я нашел несколько интересных решений:
Но эти проекты (и другие, которые я не перечислил) имеют две основные проблемы:
- Я не уверен, что они все еще поддерживаются (некоторые из них в последний раз обновлялись больше года назад)
- Ни один из них не помогает мне управлять двумя различными форматами даты для отображения и сохранения данных.
Поскольку мне нужно отобразить дату в итальянском формате (она будет одинаковой для большинства локализаций), это создает дополнительную проблему: браузеры, которые поддерживают ввод даты, возвращают значения даты в стандартном формате ISO 8601 / RFC 3339 (гггг-мм-дд ) в то время как каждый скрипт, который я проверял, использует один и тот же формат для отображения и сохранения.
Таким образом, у меня были значения, сохраненные из Chrome, Opera и большинства мобильных браузеров в формате yyyy-mm-dd
, и значения из браузеров, которые используют резервный сценарий как dd/mm/yyyy
— большой беспорядок!
А как насчет jQuery UI?
Прежде чем перейти к пользовательскому решению (я намеренно отказался от возможности управления двумя форматами в серверной части), я начал рассматривать jQuery UI Datepicker как возможное решение.
Я изначально не рассматривал jQuery UI, потому что он поставляется с некоторыми предопределенными темами, которые не интегрированы с Bootstrap (но это не было большой проблемой). С другой стороны, DatePicker пользовательского интерфейса jQuery — это хорошо протестированная и поддерживаемая библиотека, и ее опция altField
представляет именно то, что я искал. Кроме того, сценарии Bootstrap требуют jQuery, как и пользовательский интерфейс jQuery.
Пользовательский интерфейс jQuery можно загрузить со страницы проекта , но, поскольку я собираюсь смешивать файлы пользовательского интерфейса jQuery с файлами Bootstrap, я думаю, что наилучшим способом является его загрузка (или клонирование и т. д.) из репозитория GitHub .
Использование файлов разработки позволит мне проще комбинировать CSS-файлы с Bootstrap. Необходимые файлы (из основной папки пользовательского интерфейса jQuery):
- JS:
-
ui/core.js
-
ui/datepicker.js
- файл локализации из папки
ui/i18n
-
- CSS:
-
themes/base/core.css
-
themes/base/datepicker.css
-
themes/base/theme.css
.
-
Условная загрузка
Перед загрузкой скрипта обратного вызова нам необходимо проверить поддержку браузера. Простой способ сделать это — использовать функцию обнаружения с Modernizr, как и в моем предыдущем тесте, используя загрузчик ресурсов для загрузки резервных сценариев только при необходимости:
Modernizr.load({ test: Modernizr.inputtypes.date, nope: [ 'jquery-ui-master/ui/core.js', 'jquery-ui-master/ui/datepicker.js', 'jquery-ui-master/ui/i18n/datepicker-it.js', 'jquery-ui-master/themes/base/core.css', 'jquery-ui-master/themes/base/datepicker.css', 'jquery-ui-master/themes/base/theme.css' ], callback: function () { // do something if test fails } });
Сначала мы проверяем поддержку inputtypes.date
, при необходимости загружая файлы JavaScript и CSS для inputtypes.date
.
Я специально держал все файлы отдельно для ясности, но это хорошая идея объединить их в процессе сборки для производства.
Примечание: имейте в виду, что yepnope.js (компонент загрузки Modernizr) устарел , и будущие версии Modernizr не будут включать его.
После nope
скриптов nope
и css мы должны сказать нашим браузерам (тем, которые не Modernizr.inputtypes.date
тест Modernizr.inputtypes.date
) сделать что-то, поэтому мы должны добавить функцию обратного вызова:
callback:function (url) { if (url === 'jquery-ui-master/ui/i18n/datepicker-it.js') { var idx = 0; $('input[type="date"]').each( function() { var _this = $(this), prefix = 'alt' + String(idx++) + '_', _val = _this.val(); _this .attr('placeholder', 'gg/mm/aaaa') .attr('autocomplete', 'off') .prop('readonly', true) .after('<input type="hidden" id="' + prefix + _this.attr('id') + '" name="' + _this.attr('name') + '" value="' + _val + '">') .removeAttr('name') .val('') .datepicker({ altField: '#'+ prefix + _this.attr('id'), dateFormat: 'dd/mm/yy', altFormat: 'yy-mm-dd' }); // managing existing date values if (_val) { _this.datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', _val) ); } }); } }
Как работает код:
- Используя аргумент
url
, мы сначала проверяем, все ли скрипты были загружены, проверяя последний из них. - Для каждого поля
input[type="date"]
создается скрытое поле сunique-id
. - Атрибут имени поля даты удаляется и добавляется в скрытое поле.
- Виджет проинструктирован использовать скрытое поле как
altField
для хранения даты в формате ISO, независимо от используемой нами локализации. - Дата и скрытое поле форматов даты установлены.
- Любое существующее значение ISO удаляется и переназначается в формате DatePicker.
- Добавляется заполнитель с шаблоном вставляемой даты (в соответствии с нашим локальным форматом даты).
-
autocomplete
отключено, поскольку в некоторых случаях это может привести к путанице при использовании виджета. - атрибут
readonly
добавляется в поля. Это, конечно, не лучший вариант с точки зрения UX, но он решает большую проблему: если содержимое поля даты стирается вручную (без запуска виджета), поле alt не обновляется, и толькоreadonly
предотвращает такое поведение.
Вы можете увидеть результат, показанный на скриншоте ниже (я изменил altField
со hidden
на text
в серой altField
чтобы вы могли видеть изменения).
Вот страница результатов просмотра с Firefox …
… и с Chrome и IOS (которые используют свой родной виджет):
А вот демо, чтобы попробовать это самостоятельно:
Обратите внимание, что в этой демонстрации я загрузил скрипты из CDN, поэтому есть некоторые отличия от кода, показанного ранее.
Чтобы завершить обратный вызов, я добавил некоторый код для управления любыми min
или max
атрибутами (которые вы можете увидеть на вкладке «JS» демонстрации CodePen).
Интеграция с начальной загрузкой
Этот предыдущий шаг не решает проблему интеграции Bootstrap. Вы можете увидеть, как во всех примерах показана основная тема пользовательского интерфейса jQuery, загруженная через файл theme.css
. Если вы удалите его, виджет появится без какого-либо форматирования:
Поэтому мы должны заменить этот файл интегрированным с Bootstrap.
Я думаю, что есть два хороших способа сделать это:
- Создайте новый
theme.less
(или.scss
). Это лучший способ, если вам нужно использовать больше виджетов jQuery UI, так какtheme.css
совместно используется всеми ними (в этом случае посмотрите документацию по CSS jQuery UI CSS Framework ) - Создайте тему только для DatePicker, игнорируя другие виджеты. Вы должны учитывать это, если вам нужен только виджет Datepicker. Даже если этот способ более эмпирический , он действительно быстрее, чем другой (и это решение мы рассмотрим сейчас).
Это наши цели:
- Напишите новый файл
datepicker.less
используя переменные проекта Bootstrap для цвета, размеров и т. Д. Это свяжет ваш Datepicker с настройкой фреймворка, что позволит нам создать более скоординированный дизайн. - Используйте значок шрифта (в данном случае это глифы по умолчанию в Bootstrap) вместо оригинальных изображений jQuery UI.
Чтобы создать файл, сначала нужно импортировать некоторые настройки из Bootstrap. Загрузив его (и, конечно, пользовательский интерфейс jQuery), создайте новый файл less
и импортируйте variables
и glyphicons
:
@import (reference) 'path/to/bootstrap/variables.less'; @import (reference) 'path/to/bootstrap/glyphicons.less';
Опорная reference
позволяет нам «импортировать внешние файлы без добавления импортированных стилей в скомпилированный вывод, если на них нет ссылок» (см. Меньше параметров импорта ).
Затем вы должны построить файл с помощью переменных Bootstrap, как в примере ниже:
.ui-datepicker .ui-datepicker-header { background-color: @panel-default-heading-bg; border-radius: @border-radius-base; font-family: @font-family-sans-serif; color: @panel-default-text; font-weight: bold; }
Точно так же замена изображений значков на глифы очень проста:
.ui-datepicker .ui-icon { .glyphicon(); visibility: hidden; text-indent: 0; &:before { visibility: visible; } } .ui-datepicker .ui-icon.ui-icon-circle-triangle-w { .glyphicon-chevron-left(); } .ui-datepicker .ui-icon.ui-icon-circle-triangle-e { .glyphicon-chevron-right(); }
Вы можете найти полный файл less
в моем репозитории GitHub для этого решения .
Обратите внимание, что при этом полностью сохраняются исходные файлы пользовательского интерфейса jQuery , и вы можете обновлять их в любое время, не беспокоясь о потере настроек.
Таким же образом вы можете использовать любой другой значок-шрифт или спрайт изображения и настраивать переменные Bootstrap по своему усмотрению.
Вот скриншот результата:
О времени
К сожалению, jQuery UI Datepicker не управляет полями datetime
. Но я нашел очень простое решение в дополнении Timepicker Трента Ричардсона . Он ведет себя так же, как стандартный виджет datepicker.less
и использует наш файл datepicker.less без дополнительной работы.
Что дальше?
Есть несколько вещей, которые необходимо учитывать при реализации кросс-браузерного поля ввода даты / времени, и здесь невозможно охватить все вопросы. Постепенное увеличение поддержки браузерами типов ввода в конечном итоге сделает обсуждаемые здесь уловки (я надеюсь) устаревшими, и это станет намного проще.
Если у вас есть предложения или мысли о том, как вы подошли к этим проблемам, дайте мне знать в комментариях.