Работа с #хэшем в url + history api

Последний проект, который я делал состоит из одной страницы, и все действия выполняются через Ajax.
Конечно, понадобилось сохранять состояние страницы, и самое универсальное решение — хэш.

Если кто не в курсе, хэшем url зовется всё, что идет после символа #. Изначально это было придумано для якорей и используется до сих пор всякими способами из-за одной особенности — изменение хэша не обновляет страницу.

То есть, при клике на ссылку, которая ссылается на саму себя, но с хэшем — документ пролистывается до нужного места, но страница не перезагружается.

Более простого и универсального способа сохранения статуса Ajax приложений пока не придумано. Все браузеры работают с ним нативно, без заморочек.

Поэтому я написал простенький объект, методы которого позволили мне удобно работать с хэшем. Предлагаю его вам:
Hash = {
	// Получаем данные из адреса
	get: function() {
		var vars = {}, hash, splitter, hashes;
		if (!this.oldbrowser()) {
			var pos = window.location.href.indexOf('?');
			hashes = (pos != -1) ? decodeURIComponent(window.location.href.substr(pos + 1)) : '';
			splitter = '&';
		}
		else {
			hashes = decodeURIComponent(window.location.hash.substr(1));
			splitter = '/';
		}

		if (hashes.length == 0) {return vars;}
		else {hashes = hashes.split(splitter);}

		for (var i in hashes) {
			if (hashes.hasOwnProperty(i)) {
				hash = hashes[i].split('=');
				if (typeof hash[1] == 'undefined') {
					vars['anchor'] = hash[0];
				}
				else {
					vars[hash[0]] = hash[1];
				}
			}
		}
		return vars;
	},
	// Заменяем данные в адресе на полученный массив
	set: function(vars) {
		var hash = '';
		for (var i in vars) {
			if (vars.hasOwnProperty(i)) {
				hash += '&' + i + '=' + vars[i];
			}
		}

		if (!this.oldbrowser()) {
			if (hash.length != 0) {
				hash = '?' + hash.substr(1);
			}
			window.history.pushState(hash, '', document.location.pathname + hash);
		}
		else {
			window.location.hash = hash.substr(1);
		}
	},
	// Добавляем одно значение в адрес
	add: function(key, val) {
		var hash = this.get();
		hash[key] = val;
		this.set(hash);
	},
	// Удаляем одно значение из адреса
	remove: function(key) {
		var hash = this.get();
		delete hash[key];
		this.set(hash);
	},
	// Очищаем все значения в адресе
	clear: function() {
		this.set({});
	},
	// Проверка на поддержку history api браузером
	oldbrowser: function() {
		return !(window.history && history.pushState);
	},
};

Внимание! Объект был переписан и работает теперь через history api, по возможности. Если нет — то через хэш, как раньше.
Это означает, что в современных браузерах будут прямые адреса типа
test.ru/?var1=1&var2=2
А в IE8 и ниже
test.ru/#var1=1&var2=2

Метод Hash.oldbrowser() определяет режим работы. Вы можете перезагружать страницу при переходе на адрес с хэшем, если нужно:
if (window.location.hash != '' && Hash.oldbrowser()) {
	var uri = window.location.hash.replace('#', '?');
	window.location.href = document.location.pathname + uri;
}
Так, например, работает mSearch2 при фильтрации.

Сохраняем это в javascript файл, и можно пользоваться методами Hash.get(), Hash.set() и т.д.

Теперь пример использования. Предположим, мы хотим, чтобы при клике на ссылку с классом alert у нас происходило событие — окно с алертом:
$(document).on('click', 'a.alert', function(e) {
	alert('Событие!');
});

А теперь мы хотим дать прямую ссылку на этот алерт, чтобы любой, кто по ней перейдет увидел его, без клика:
// Обрабатываем клик по сслылке
$(document).on('click', 'a.alert', function(e) {
	Hash.add('event', 'alert');	// добавляем в хэш #event=alert
	alert('Событие!');
});
// Проверяем, что есть в хэше при загрузке страницы
$(document).ready(function() {
	var hash = Hash.get();	// получаем все значения
	if (hash.anchor) {
		window.location.hash = hash.anchor; // сохраняем родной функционал якорей
	}
	else if (hash.event == 'alert') {	// если есть событие alert - как бы кликаем по нужной ссылке
		$('a.alert').trigger('click');
	}
})

Вот так просто. Код для сохранения статуса табов:
// Обработка табов
$(document).on('click', '.nav a[data-toggle="tab"]', function (e) {
	e.preventDefault();
	var href = $(this).attr('href').substr(1);
	Hash.add('tab', href);
});
// Переключение таба при загрузке страницы
$(document).ready(function() {
	var hash = Hash.get();
	if (hash.tab) {
		$('.nav a[href="#' + hash.tab + '"]').trigger('click');
	}
})
Василий Наумкин
31 декабря 2012, 08:26
modx.pro
7
26 374
0

Комментарии: 14

Александр Балагуров
31 декабря 2012, 13:34
0
Все это фигня. Захешенные страницы нужно отдавать по другому спец урлу для индексации поисковиками, а это лишний гемор. В итоге я свой аналогичный проект переписал на history.js
    Василий Наумкин
    31 декабря 2012, 14:03
    0
    Речь про состояние переключенных табов, всплывших окошек, или кнопок фильтров.

    Причем тут индексация?
    Виталий Воропаев
    31 декабря 2012, 14:52
    0
    С точки зрения организации кода, все четко. Аккуратно и ничего лишнего.
      Denys Butenko
      02 января 2013, 17:07
      0
      Если с главной страницы нажать кнопку «Читать дальше», страница открывается с хэшем #cut и на этой странице справа менять вкладки «Комметарии» и «Публикации» в адресной строке появляется это:
      http://modx.pro/development/520/#cut=undefined/tab=tickets
        Василий Наумкин
        02 января 2013, 18:50
        0
        Принято, спасибо.

        Подумаю на досуге, как разделить хэш для собственных нужд и настоящие якоря.
          Василий Наумкин
          03 января 2013, 11:05
          0
          Дописал обработку якорей.

          Теперь, если что, они сохраняются в #anchor=имяякоря. Если при загрузке есть такое значение в хэше — то оно перекрывает остальные и хэш меняется на якорь.

          Пытался подружить это дело с scrollTo.js, чтобы перекручивало на якорь и срабатывали остальные параметры — но глюки не смог одолеть. Поэтому теперь так: реальный якорь важнее остального.

          Проверяем — bezumkin.ru/sections/components/516/#anchor=cut/tab=tickets
          Влад Козьяков
          02 апреля 2013, 07:50
          0
          Василий, у вас небольшая ошибка в тексте сообщения:

          после вставки первого кода
          Сохраняем это в javascript файл, и можно пользоваться методами Hah.get(), Hash.set() и т.д.
          букву s пропустили)

          п.с.
          Много полезного у вас на ресурсе, спасибо за множество интересной информации =)
          Сергей Шлоков
          07 мая 2013, 19:06
          0
          Нужная вещь. Очень обрадовался. Взял для табов. Но как у тебя не работает. :( Мой страница с табами. Вроде все по инструкции, но не работает.
          П.С. Использую скрипт Organictab. Может он виноват?
            Василий Наумкин
            07 мая 2013, 19:11
            0
            У тебя все события перехватывает скрипт табов. Смотри, как ему задать callback на переключение.

            Проверять, срабатывает событие, или нет, можно простым alert().
              Сергей Шлоков
              07 мая 2013, 19:30
              0
              Понял. А у тебя что за скрипт табы обрабатывает, если не секрет?
                Сергей Шлоков
                07 мая 2013, 23:32
                0
                При полном отсутствии знаний по js допилил — работает! Извиняюсь за ламерские вопросы, я не программист.
              Это сообщение было удалено
                DeDMazday
                08 ноября 2015, 14:55
                0
                К сожалению я совсем не программист, и представленный код понимаю в лучшем случае на треть, и пользователь я не modx, а joomla, хотя для этого кода вроде бы всё равно должно быть. Попробовал прикрутить на страницу — не работает, ошибок не пишет, но и не работает, к сожалению понять что именно не пашет не разобраться, может гляните? Код в принципе интересный, и хотелось бы его попользовать.
                ЗЫ сайт на который пытался приделать travelsbase.ru
                  Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                  14