Кнопка «наверх» – мелочь, а удобно, реализация на Prototype.js

в 7:41, , рубрики: javascript, Веб-разработка, интерфейсы, юзабилити интерфейсов, метки: ,

imageВообще-то для этого существует комбинация клавиш Ctrl + Home — в самый вверх, и Ctrl + End — в самый низ, если кто не знает или не помнит. Но ещё бывает лень потянуться к клавиатуре чтобы нащупать соответстующие кнопки, особенно когда сидишь откинувшись в кресле, а в руках чашка с кофе. Что касается обычных, в том числе «непродвинутых» юзеров, так им и дела нет до каких-то сочетаний и комбинаций.

По всей видимости, чтобы облегчить жизнь людям, сберечь их время и силы придумали такие интерфейсные элементы. На многих сайтах сейчас можно встретить кнопку «наверх» в самых разных местах страницы, её лепят куда угодно, как правило, в один из углов страницы.

Единого стандарта нет, и быть не может, но давайте всё-таки обозначим несколько основных требований:

  1. Кнопка хорошо заметна, в то же время не «мозолит» глаза.
  2. В неё удобно попадать мышкой, не особо целясь.
  3. Появляется тогда, когда это необходимо.
  4. Имеет единое местоположение на всех страницах.
  5. По возможности имеет возможность скрытия.

На мой взгляд, удачно сделано на vk.com и здесь, на Хабре. Сабж представляет из себя появляющуюся при наведении курсора боковую панель. По клику в любой области можно переместиться в топ, и вернуться обратно, в то место откуда прокрутил наверх. Когда привыкаешь ей пользоваться, то замечаешь, что на других сайтах этой штуки не хватает.

Теперь я расскажу как воспроизвёл данный функционал с помощью фреймворка Prototype.js. Для тех, кто не знаком: удобство этой библиотеки в том, что она позволяет программировать на javascript в стиле классического ООП. Конечно, условно, так как там много чего нет, например private методов и свойств, зато можно реализовать наследование или объявить статические переменные класса.

Нам понадобится еще одна библиотека, которая будет работать в паре с Prototype — script.aculo.us, она будет выполнять «хитрый» скролл.

Особенности нашей кнопки:

  • Будет появляться постепенно, по мере прокрутки. С того момента, как будет откручено min пикселей кнопка начнет появляться, и на max станет полностью непрозрачной (будет изменяться свoйство css opacity). Соответственно, в направлении вверх, будет плавно исчезать.
  • Страница НЕ будет прокручиваться от начала и до конца, мелькая всем содержимым перед глазами. Вместо этого перескочит, и затем плавно пройдёт пару десятков пикселей (brakingDistance) к установленному месту, чтобы было интуитивно понятно в каком направлении выполняется прокрутка.

Далее, код html, css и javascript. Полагаю, там всё предельно понятно, небольшие комментарии внутри.

HTML

<div class="toTop" id="toTop">
	<div class="toTopPanel" id="ttPanel">
		<img src="images/scrollTop.gif" width="40" height="40" class="toTopButton" id="ttButton">
		<img src="images/scrollBack.gif" width="40" height="40" class="toTopBack" id="ttBackButton">
	</div>
</div>

CSS

.toTop {
    bottom: 0;
    display: none;
    left: 0;
    display:block;
    position: fixed;
    top: 0;
    width: 40px;
    height: 100%;
    opacity:0.5;
}
.toTop:hover {
	opacity:1;
}
.toTop .toTopPanel {
    height: 100%;
    background:transparent;
    cursor: pointer;
}
.toTop .toTopPanel:hover {
	background: none repeat scroll 0 0 #dfdfcc;
}
.toTop .toTopButton, .toTop .toTopBack  {
	position: absolute;
	top:50%;
}

JavaScript

var toTop = Class.create();
toTop.prototype = {
	initialize: function(params) {
		// значения по умолчанию
		this.min = 200;
		this.max = 600;
		this.brakingDistance = 20;
		this.scrollDuration = '0.1';
		// поехали
		Object.extend(this, params);
		var that = this;
		this.holder = $(this.holder);
		this.lastPosition = false;
		['ttPanel', 'ttButton', 'ttBackButton'].each(function(name) {
			that[name] = that.getById(name);
		});
		this.ttPanel.observe('click', this.scroll.bindAsEventListener(this));
		this.panelBehavior();
		Event.observe(window, 'scroll', this.panelBehavior.bindAsEventListener(this));
		// шаман-маман
		this.ttPanel.observe('mouseover', function(){
			that.ttButton.setStyle({opacity:''});
			that.over = true;
		});
		this.ttPanel.observe('mouseout', function(){
			that.panelBehavior();
			that.over = false;
		});
	},
	
	// получить элемент по id внутри holder
	getById: function(name) {
		return (el = this.holder.select('[id="'+name+'"]')) ?  el[0] : false;
	},

	// упаравление поведением панели
	panelBehavior: function () {
		var scrOffst = document.viewport.getScrollOffsets(),
			top = scrOffst.top,
			bb = this.ttBackButton,
			tb = this.ttButton;
		if (top < this.min) {
			if (this.lastPosition) {
				bb.show();
				tb.hide();
			} else
				this.ttPanel.hide();
			return;
		}
		this.lastPosition = false;
		bb.hide();
		tb.show();
		if ((top < this.max) && !this.over) 
			tb.setOpacity((1 - (this.max - top)/(this.max - this.min)));
		else
			tb.setStyle({opacity:''});
		this.ttPanel.show();
	},

	// прокрутка вверх/вниз
	scroll: function() {
		var scrOffst = document.viewport.getScrollOffsets(),
			top = scrOffst.top,
			body = $$('body')[0],
			st = Effect.ScrollTo,
			dr = this.scrollDuration,
			lp = this.lastPosition,
			bd = this.brakingDistance;
		// скролл с "доводкой"
		if ((top < this.min) && this.lastPosition) {
			st(body, {duration:0, offset: (lp - bd), afterFinish:function(){
				st(body, {duration:dr, offset: lp});
			}});
		} else {
			st(body, {duration:0, offset:bd, afterFinish:function(){
				st(body, {duration:dr});
			}});
			this.lastPosition = top;
		}
	}
};

Примеры вызова:

new toTop({
	holder: 'toTop'
});

new toTop({
	holder: 'toTop',
	min: 300,
	max: 800,
	brakingDistance: 50;
});

Посмотреть как всё это выглядит можно здесь: zavtraka.net

Документацию по Prototype.js можно почитать здесь: api.prototypejs.org

Скачать последние версии библиотек: prototypejs.org/download/, script.aculo.us/downloads

Автор: ekokh

Источник

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


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