PickMeUp — хороший jQuery datepicker plugin

от автора

Проблема

Начиная работу над очередным сайтом понадобился datepicker. Самый известный такой datepicker — в jQuery UI, но так как jQuery UI в проекте не использовался — тянуть даже его часть не хотелось, принялся за поиски достойной альтернативы.

Требования следующие:

  • Выбор даты, нескольких дат, интервала
  • Простота настройки внешнего вида
  • Желательно без каких-либо зависимостей кроме jQuery

Требования вполне логичные, ничего сверх естественного.
Каково было мое удивление, когда просмотрев десятка два плагинов я не нашел подходящего.

Для любопытных — сразу демо того, что получилось в результате.

Ближе всех к требованиям оказался DatePicker.
Но у него было несколько недостатков:

  • Избыточная табличная верстка
  • Старый стиль оформления картинками
  • Просто старый, не развивался с 2009 года
  • Несколько досадных багов

Решить их можно было кое-как разово, но было решено довести до ума, ведь не последний проект, да и другим может пригодиться.

Велосипед, так велосипед

Первое что захотелось изменить — убрать картинки для округления краев. Но картинки в ячейках таблицы. Убрал ячейки — отвалилась почти вся функциональность… Но ведь пути назад нет!

Потом пошел рефакторинг некоторых вещей, исправление багов, добавление мелких фич, снова исправление багов, и так по кругу.
На всё ушло около двух полных дней, и оно того стоило.

Что получилось

Как пример привожу код, генерируемый оригинальным DatePicker:

Скрытый текст

<div class="datepicker" id="datepicker_828" style="display: block; position: relative; width: 196px; height: 148px;">   <div class="datepickerBorderT"></div>   <div class="datepickerBorderB"></div>   <div class="datepickerBorderL"></div>   <div class="datepickerBorderR"></div>   <div class="datepickerBorderTL"></div>   <div class="datepickerBorderTR"></div>   <div class="datepickerBorderBL"></div>   <div class="datepickerBorderBR"></div>   <div class="datepickerContainer" style="width: 176px; height: 128px;">     <table cellspacing="0" cellpadding="0">       <tbody>         <tr>           <td>             <table cellspacing="0" cellpadding="0" class="datepickerViewYears">               <thead>                 <tr>                   <th class="datepickerGoPrev">                     <a href="#">                       <span>◀</span>                     </a>                   </th>                   <th colspan="6" class="datepickerMonth">                     <a href="#">                       <span>2002 - 2013</span>                     </a>                   </th>                   <th class="datepickerGoNext">                     <a href="#">                       <span>▶</span>                     </a>                   </th>                 </tr>                 <tr class="datepickerDoW">                   <th>                     <span>wk</span>                   </th>                   <th>                     <span>Mo</span>                   </th>                   <th>                     <span>Tu</span>                   </th>                   <th>                     <span>We</span>                   </th>                   <th>                     <span>Th</span>                   </th>                   <th>                     <span>Fr</span>                   </th>                   <th>                     <span>Sa</span>                   </th>                   <th>                     <span>Su</span>                   </th>                 </tr>               </thead>               <tbody class="datepickerMonths">                 <tr>                   <td colspan="2">                     <a href="#">                       <span>Jan</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Feb</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Mar</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Apr</span>                     </a>                   </td>                 </tr>                 <tr>                   <td colspan="2">                     <a href="#">                       <span>May</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Jun</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Jul</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Aug</span>                     </a>                   </td>                 </tr>                 <tr>                   <td colspan="2">                     <a href="#">                       <span>Sep</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Oct</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Nov</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>Dec</span>                     </a>                   </td>                 </tr>               </tbody>               <tbody class="datepickerDays">                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>27</span>                     </a>                   </th>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>30</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>1</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>2</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>3</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>4</span>                     </a>                   </td>                   <td class="datepickerSaturday">                     <a href="#">                       <span>5</span>                     </a>                   </td>                   <td class="datepickerSunday">                     <a href="#">                       <span>6</span>                     </a>                   </td>                 </tr>                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>28</span>                     </a>                   </th>                   <td class="">                     <a href="#">                       <span>7</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>8</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>9</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>10</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>11</span>                     </a>                   </td>                   <td class="datepickerSaturday">                     <a href="#">                       <span>12</span>                     </a>                   </td>                   <td class="datepickerSunday">                     <a href="#">                       <span>13</span>                     </a>                   </td>                 </tr>                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>29</span>                     </a>                   </th>                   <td class="">                     <a href="#">                       <span>14</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>15</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>16</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>17</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>18</span>                     </a>                   </td>                   <td class="datepickerSaturday">                     <a href="#">                       <span>19</span>                     </a>                   </td>                   <td class="datepickerSunday">                     <a href="#">                       <span>20</span>                     </a>                   </td>                 </tr>                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>30</span>                     </a>                   </th>                   <td class="">                     <a href="#">                       <span>21</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>22</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>23</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>24</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>25</span>                     </a>                   </td>                   <td class="datepickerSaturday">                     <a href="#">                       <span>26</span>                     </a>                   </td>                   <td class="datepickerSunday">                     <a href="#">                       <span>27</span>                     </a>                   </td>                 </tr>                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>31</span>                     </a>                   </th>                   <td class="">                     <a href="#">                       <span>28</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>29</span>                     </a>                   </td>                   <td class="">                     <a href="#">                       <span>30</span>                     </a>                   </td>                   <td class="datepickerSelected">                     <a href="#">                       <span>31</span>                     </a>                   </td>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>1</span>                     </a>                   </td>                   <td class="datepickerNotInMonth datepickerSaturday">                     <a href="#">                       <span>2</span>                     </a>                   </td>                   <td class="datepickerNotInMonth datepickerSunday">                     <a href="#">                       <span>3</span>                     </a>                   </td>                 </tr>                 <tr>                   <th class="datepickerWeek">                     <a href="#">                       <span>32</span>                     </a>                   </th>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>4</span>                     </a>                   </td>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>5</span>                     </a>                   </td>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>6</span>                     </a>                   </td>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>7</span>                     </a>                   </td>                   <td class="datepickerNotInMonth">                     <a href="#">                       <span>8</span>                     </a>                   </td>                   <td class="datepickerNotInMonth datepickerSaturday">                     <a href="#">                       <span>9</span>                     </a>                   </td>                   <td class="datepickerNotInMonth datepickerSunday">                     <a href="#">                       <span>10</span>                     </a>                   </td>                 </tr>               </tbody>               <tbody class="datepickerYears">                 <tr>                   <td colspan="2">                     <a href="#">                       <span>2002</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2003</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2004</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2005</span>                     </a>                   </td>                 </tr>                 <tr>                   <td colspan="2">                     <a href="#">                       <span>2006</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2007</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2008</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2009</span>                     </a>                   </td>                 </tr>                 <tr>                   <td colspan="2">                     <a href="#">                       <span>2010</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2011</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2012</span>                     </a>                   </td>                   <td colspan="2">                     <a href="#">                       <span>2013</span>                     </a>                   </td>                 </tr>               </tbody>             </table>           </td>         </tr>       </tbody>     </table>   </div> </div> 

и код, генерируемый PickMeUp:

Скрытый текст

<div class="pickmeup pmu-view-days" style="position: relative; display: inline-block;">   <div class="pmu-instance">     <nav>       <div class="pmu-prev pmu-button">◀</div>       <div class="pmu-month pmu-button">November, 2013</div>       <div class="pmu-next pmu-button">▶</div>     </nav>     <nav class="pmu-day-of-week">       <div>Mo</div>       <div>Tu</div>       <div>We</div>       <div>Th</div>       <div>Fr</div>       <div>Sa</div>       <div>Su</div>     </nav>     <div class="pmu-months">       <div class="pmu-button">Jan</div>       <div class="pmu-button">Feb</div>       <div class="pmu-button">Mar</div>       <div class="pmu-button">Apr</div>       <div class="pmu-button">May</div>       <div class="pmu-button">Jun</div>       <div class="pmu-button">Jul</div>       <div class="pmu-button">Aug</div>       <div class="pmu-button">Sep</div>       <div class="pmu-button">Oct</div>       <div class="pmu-button">Nov</div>       <div class="pmu-button">Dec</div>     </div>     <div class="pmu-days">       <div class="pmu-not-in-month pmu-button">28</div>       <div class="pmu-not-in-month pmu-button">29</div>       <div class="pmu-not-in-month pmu-button">30</div>       <div class="pmu-not-in-month pmu-button">31</div>       <div class=" pmu-button">1</div>       <div class="pmu-saturday pmu-button">2</div>       <div class="pmu-sunday pmu-button">3</div>       <div class=" pmu-button">4</div>       <div class=" pmu-button">5</div>       <div class=" pmu-button">6</div>       <div class=" pmu-button">7</div>       <div class=" pmu-button">8</div>       <div class="pmu-saturday pmu-button">9</div>       <div class="pmu-sunday pmu-button">10</div>       <div class=" pmu-button">11</div>       <div class=" pmu-button">12</div>       <div class=" pmu-button">13</div>       <div class=" pmu-button">14</div>       <div class=" pmu-button">15</div>       <div class="pmu-saturday pmu-button">16</div>       <div class="pmu-sunday pmu-button">17</div>       <div class="pmu-selected pmu-button">18</div>       <div class=" pmu-button">19</div>       <div class=" pmu-button">20</div>       <div class=" pmu-button">21</div>       <div class=" pmu-button">22</div>       <div class="pmu-saturday pmu-button">23</div>       <div class="pmu-sunday pmu-button">24</div>       <div class=" pmu-button">25</div>       <div class=" pmu-button">26</div>       <div class=" pmu-button">27</div>       <div class=" pmu-button">28</div>       <div class=" pmu-button">29</div>       <div class="pmu-saturday pmu-button">30</div>       <div class="pmu-not-in-month pmu-sunday pmu-button">1</div>       <div class="pmu-not-in-month pmu-button">2</div>       <div class="pmu-not-in-month pmu-button">3</div>       <div class="pmu-not-in-month pmu-button">4</div>       <div class="pmu-not-in-month pmu-button">5</div>       <div class="pmu-not-in-month pmu-button">6</div>       <div class="pmu-not-in-month pmu-saturday pmu-button">7</div>       <div class="pmu-not-in-month pmu-sunday pmu-button">8</div>     </div>     <div class="pmu-years">       <div class="pmu-button">2007</div>       <div class="pmu-button">2008</div>       <div class="pmu-button">2009</div>       <div class="pmu-button">2010</div>       <div class="pmu-button">2011</div>       <div class="pmu-button">2012</div>       <div class="pmu-button">2013</div>       <div class="pmu-button">2014</div>       <div class="pmu-button">2015</div>       <div class="pmu-button">2016</div>       <div class="pmu-button">2017</div>       <div class="pmu-button">2018</div>     </div>   </div> </div> 

Код не идеален, но намного проще и понятнее, а значит и оформлять его проще.

Что ещё нового по сравнению с оригиналом:

  • Поддержка указания конфигурационных опций в data-атрибутах
  • Глобальная конфигурация плагина
  • Независимость языка каждого отдельного календаря
  • Стили в маленьком scss файле с конфигурационными переменными — если нужно только изменить цвета — идеально подходит
  • Макет резиновый, размер зависит от размера шрифта корневого элемента, выглядит одинаково хорошо при любом размере шрифта
  • Размер плагина меньше оригинала
  • Все классы имеют префикс pmu-, корневой элемент имеет класс pickmeup
  • Кое-какие мелочи

Так выглядит содержимое scss файла:

$border-radius						: .4em; $background							: #000; $color								: #eee; $color-hover						: #88c5eb; $nav-color							: $color; $nav-color-hover					: $color-hover; $not-in-month						: #666; $not-in-month-hover					: #999; $disabled							: #333; $selected-background 				: #136a9f; $not-in-month-selected-background	: #17384d; $day-of-week						: $not-in-month-hover;  @mixin display-flex() { 	display : -ms-flexbox; 	display : -webkit-flex; 	display : flex; }  .pickmeup { 	background    : $background; 	border-radius : $border-radius; 	display       : none; 	position      : absolute;  	* { 		-moz-box-sizing : border-box; 		box-sizing      : border-box; 	}  	.pmu-instance { 		display    : inline-block; 		height     : 13.8em; 		padding    : .5em; 		text-align : center; 		width      : 15em;  		.pmu-button { 			color           : $color; 			cursor          : pointer; 			outline         : none; 			text-decoration : none; 		}  		.pmu-button:hover { 			color : $color-hover; 		}  		.pmu-not-in-month { 			color : $not-in-month; 		}  		.pmu-disabled, 		.pmu-disabled:hover { 			color  : $disabled; 			cursor : default; 		}  		.pmu-selected { 			background : $selected-background; 		}  		.pmu-not-in-month.pmu-selected { 			background : $not-in-month-selected-background; 		}  		nav { 			@include display-flex(); 			color       : $nav-color; 			line-height : 2em;  			*:hover { 				color : $nav-color-hover; 			}  			.pmu-prev, 			.pmu-next { 				height : 2em; 				width  : 1em; 			} 			.pmu-month { 				width : 12em; 			} 		}  		.pmu-years, 		.pmu-months { 			* { 				display     : inline-block; 				line-height : 3.6em; 				width       : 3.5em; 			} 		}  		.pmu-day-of-week { 			color  : $day-of-week; 			cursor : default; 		}  		.pmu-day-of-week, 		.pmu-days { 			* { 				display     : inline-block; 				line-height : 1.5em; 				width       : 2em; 			} 		}  		.pmu-day-of-week * { 			line-height : 1.8em; 		} 	}  	&:not(.pmu-view-days) .pmu-days, 	&:not(.pmu-view-days) .pmu-day-of-week, 	&:not(.pmu-view-months) .pmu-months, 	&:not(.pmu-view-years) .pmu-years { 		display : none; 	} } 

Итог

Размер минифицированного плагина:
* 14.8 KiB JavaScript (4.2 KiB gzip)
* 1.8 KiB CSS (650 B gzip)

C целью упрощения верстки поддерживается IE10+, и актуальные версии других браузеров (при желании можно сделать поддержку IE9-, но у меня такого желания нет, написал всё-таки в первую очередь для себя).

Демо Репозиторий на GitHub

Искренне надеюсь, кому-то кроме меня этот jQuery плагин пригодится, буду рад конструктивной критике и pull request-ам.

В ближайшем будущем можно встроить другие локализации, в репозитории bootstrap-datepicker их много разных.

ссылка на оригинал статьи http://habrahabr.ru/post/202640/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *