Скроллинг контента методом касания и перетаскивания на jQuery

в 8:53, , рубрики: javascript, jquery, scrolling

Hello, jQuery, again! Посвящено тем сенсорным сингл тач экранам, которые еще не канули в лету и поддерживают события mouseDown и иже с ними. Именно таким оказался информационный терминал, на котором нужно было демонстрировать контент сайта.

Задача данного плагина — скроллинг контента посредством касания одним пальцем на сингл тач сенсорном экране.

Используемые событияmouseDown/Move/Out. По умолчанию эта цепочка событий выделяет содержимое в пределах касания.

Реализация — до боли знакомое overflow:hidden, обертывание содержимого элемента и перемещение контента внутри.

Нерешенные проблемы — иногда, на грани между пересечением нижнего края и пятикратным замедлением, контент сдвигается вверх на определенный интервал. Примечательно, что при обратном движении (в момент пересечения этой черты) контент возвращается на свое место (сдвигается вниз).

Надеюсь, для кого-нибудь эта статья окажется полезной и найдет своё применение.
Вэлком в комментарии, жду ваши мысли, ваш конструктив и негатив, всё, что направлено на улучшение данного кода!

Испытательный стенд на jsFiddle (48 строк некомментированного кода).

Начнем с разметки. У нас есть блок с контентом:

<div id="content">
	<h2>Touch and drag content</h2>
	<p>Lorem ipsum dolor sit amet...</p>
</div>

#content {
	position:absolute;
	left:50px;
	top:50px;
	width:500px;
	height:350px;
	text-align:justify;
}

Далее — подробное комментирование каждого действия.

// оборачиваем плагин в анонимную функцию
(function($){
// пишем функцию с именем нашего плагина
$.fn.touchanddrag = function(){
	// оборачиваем содержимое нашего элемента в дочерний элемент, который и будем перемещать
	// исходный же элемент сохраняет свою разметку и свойства, заданные ему в css
	this.wrapInner('<div>');
	// исходный элемент теперь стал контейнером, а новый элемент - обертка для его данных
	// то есть исходный элемент (box) - родитель, а новый элемент (data) - дочерний
	var box = this,
		data = this.children();
	// прячем полосу прокрутки
	box.css({'overflow':'hidden'});
	// позиционируем элемент data
	data.css({'position':'absolute','cursor':'default'});
	// событие касания на элементе
	data.mousedown(function(e){
		// высота элементов для дальнейших вычислений
		var hgtBox = box.height(),
			hgtData = data.height();
		// проверяем, достаточно ли контента для прокрутки
		if (hgtData>hgtBox) {
			// позиция касания
			var posTap = e.pageY,
				// позиция элемента data относительно элемента box
				posData = data.position().top,
				posShift,
				// событие скольжения в пределах документа
				mouseMove = function(e){
					// расстояние, пройденное относительно первого касания
					posShift = e.pageY-posTap;
					// если прокрутили контент выше верхнего края
					if (data.position().top>0){
						// перемещаем контент, но в 5 раз медленнее
						// фрагмент имитации кинетической прокрутки
						data.css({'top':(posData+posShift)/5});
					// если прокрутили контент ниже нижнего края
					} else if ((data.position().top+hgtData)<hgtBox){
						// замедляем перемещение в пять раз
						data.css({'top':(hgtBox-hgtData)+(posShift/5)});
					// прокрутка контента в пределах видимости родителя
					} else {
						// добавляем разницу к предыдущим координатам
						data.css({'top':posData+posShift});
					}
				},
				// событие отпускания
				mouseUp = function(){
					// отменяем мониторинг перетаскивания и блокировку выделения
					$(document).off('mousemove',mouseMove).off('mouseup',mouseUp);
					$(document).off('mousedown',selection);
					// возвращаем вид курсора
					data.css({'cursor':'default'});
					// если после прокрутки контент оказался выше верхнего края						
					if (data.position().top>0){
						// плавно возвращаем его в крайнюю верхнюю позицию
						// фрагмент имитации кинетической прокрутки
						data.animate({'top':0},250);
					// если после прокрутки контент оказался ниже нижнего края
					} else if ((data.position().top+hgtData)<hgtBox) {
						// плавно возвращаем его в крайнюю нижнюю позицию
						data.animate({'top':hgtBox-hgtData},250);
					}
				},
				// снятие выделения при перетаскивании контента
				selection = function(){
					if (window.getSelection){window.getSelection().removeAllRanges()}
					else {document.selection.empty()}
					return false;
				};
			// меняем вид курсора на время перетаскивания
			data.css({'cursor':'move'});
			// инициализируем мониторинг перетаскивания и блокировку выделения
			$(document).on('mousedown',selection).on('mousemove',mouseMove);
			$(document).on('mouseup',mouseUp).on('contextmenu',mouseUp);
			$(window).on('blur',mouseUp);
		}
	});
	return this;
};
})(jQuery);

Вызываем плагин:

$('#content').touchanddrag();

Автор: rafaylik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js