Моя работа часто требует добавления даты ввода в формы. Поскольку они еще не поддерживаются всеми браузерами, я всегда ищу лучший способ интегрировать их в свои страницы.
Вы можете увидеть последние данные о поддержке браузером для ввода даты на я могу использовать .
В дополнение к основному полю 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 без дополнительной работы.
Что дальше?
Есть несколько вещей, которые необходимо учитывать при реализации кросс-браузерного поля ввода даты / времени, и здесь невозможно охватить все вопросы. Постепенное увеличение поддержки браузерами типов ввода в конечном итоге сделает обсуждаемые здесь уловки (я надеюсь) устаревшими, и это станет намного проще.
Если у вас есть предложения или мысли о том, как вы подошли к этим проблемам, дайте мне знать в комментариях.




