Альтернатива .sortable — новое решение сортировки списка на jQuery

от автора

Существует масса решений для сортировки списков, например tableDTD, tableSorter, jQuery.sortable и прочих, которые имеют широкий функционал, но при этом — большой код.
Моё решение использует jQuery, имеет компактный код (42 строки без комментариев) и предусматривает перемешивание элементов (относительно позиционированных) в пределах родительского контейнера.
Весь ход мыслей прокомментирован в JavaScript.

Посмотреть в действии на jsFiddle (некомментированный код).

HTML-разметка

<!DOCTYPE html> <html><head>  	<meta charset='utf-8'> 	<link type='text/css' rel='stylesheet' href='style.css'> 	<script type='text/javascript' src='http://code.jquery.com/jquery-2.0.3.min.js'></script> 	<script type='text/javascript' src='actions.js'></script>  </head><body>  <div class="container"> 	<div class="drop">1</div> 	<div class="drop">2</div> 	<div class="drop">3</div> 	<div class="drop">4</div> 	<div class="drop">5</div> </div> <input class="focus-out">  </body></html> 

style.css

.container {width:200px;} .drop {position:relative; top:0px; height:16px; cursor:default; z-index:1;} .focus-out {position:absolute; width:2px; height:2px; left:-10px; top:-10px; background:none;} 

actions.js

$(document).ready(function(){  	// нажали на любом элементе списка 	$('.drop').mousedown(function(e){ 		var drop = $(this); 		// верхняя граница контейнера 		var posParentTop = drop.parent().position().top; 		// нижняя граница контейнера 		var posParentBottom = posParentTop + drop.parent().height(); 		// координаты исходного положения элемента 		var posOld = drop.position().top; 		// коррекция относительно позиции курсора при нажатии 		var posOldCorrection = e.pageY - posOld; 		// поднимаем нажатый элемент по z-оси 		drop.css({'z-index':2, 'background-color':'#eeeeee'}); 		// перетягиваем элемент 		var mouseMove = function(e){ 			// получаем новые динамические координаты элемента 			var posNew = e.pageY - posOldCorrection; 			// если элемент перетянут выше верхней границы контейнера 			if (posNew < posParentTop){ 				// устанавливаем позицию элемента, равную позиции родителя 				drop.offset({'top': posParentTop}); 				// отменяем выделение, переместив фокус в спрятанный (но не скрытый через css) input 				$('.focus-out').focus(); 			// если элемент перетянут ниже нижней границы контейнера 			} else if ((posNew + drop.height()) > posParentBottom){ 				// устанавливаем позицию элемента, равную позиции родителя + высоте родителя - высоте элемента 				drop.offset({'top': posParentBottom - drop.height()}); 				// отменяем выделение 				$('.focus-out').focus(); 			// если элемент в пределах контейнера 			} else { 				// устанавливаем новую высоту (элемент перемещается за курсором) 				drop.offset({'top': posNew}); 				// если элемент перемещен вверх на собственную высоту 				if (posOld - posNew > drop.height() - 2){ 					// меняем элемент с предыдущим в DOM 					drop.insertBefore(drop.prev()); 					// обнуляем позицию 					drop.css({'top':0}); 					// снова получаем координаты исходного и текущего положения 					posOld = drop.position().top; 					posNew = e.pageY - posOldCorrection; 					posOldCorrection = e.pageY - posOld; 				// если элемент перемещен вниз на собственную высоту 				} else if (posNew - posOld > drop.height() - 2){ 					// меняем элемент со следующим в DOM 					drop.insertAfter(drop.next()); 					drop.css({'top':0}); 					posOld = drop.position().top; 					posNew = e.pageY - posOldCorrection; 					posOldCorrection = e.pageY - posOld; 				} 				// отменяем выделение 				$('.focus-out').focus(); 			} 		}; 		// отпускаем клавишу мыши 		var mouseUp = function(){ 			// завершаем выполнение функции 			$(document).off('mousemove', mouseMove).off('mouseup', mouseUp); 			// плавно возвращаем наш элемент на ближайшее освободившееся место 			drop.animate({'top':0}, 100); 			// возвращаем z-позицию на уровень остальных элементов 			setTimeout(function(){ 				drop.css({'z-index':1, 'background-color':'transparent'}); 			}, 100); 		}; 		// подключаем выполнение функций перемещения и отпускания клавиши мыши 		// и завершаем выполнение функции, если нажата правая клавиша мыши 		$(document).on('mousemove', mouseMove).on('mouseup', mouseUp).on('contextmenu', mouseUp); 	});  }); 

Нерешённый вопрос: снимать выделение без использования спрятанного input (это простой путь, но совсем не феншуй). Кто что думает по поводу user-select?

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


Комментарии

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

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