09 марта (обновлено 10 мая)

Покайтесь, ибо конец близок!

Это небольшой отчет о проекте http://the-end.info

Для начала, пара слов о целях и задачах, которые ставились перед ним. Мы хотели создать интересный с технической точки зрения и необычный сайт, дабы хоть и косвенно, но заявить о себе. Отчасти, нам это удалось - в наш адрес (а точнее адрес сайта) мы слышали в основном положительные отзывы, негатив исходил лишь от противников Конца света как такового.

Первоначально пришла идея создания апокалипсических календарей на 2012 г., но по ходу развития идеи, она уже не могла уложиться в рамки 10х6 см и тогда было решено сделать сайт.

а теперь, обещанный "отчет" и некоторые, на мой взгляд, интересные приемы:

Итак, думаю, стоит начать с того, что размеры окна браузера берутся как основная ширина и высота, от которых уже все и отталкивается:

if ($(window).width() >1000)
max_w = $(window).width();
else
max_w = 1000;
max_h = $(window).height();

Это весьма удобный прием, он прост и очевиден, однако следует отметить, что эти параметры (а, следовательно, и все зависимые) необходимо пересчитать при изменении размеров окна браузера, повесив их на событие

$(window).resize();

В этом примере для обработки всех зависимых переменных используется функция on_resize(), которая вызывается при первоначальной загрузке страницы и при изменении окна браузера. Наиболее интересным в этой функции является «рисование звезд». Очень простой и незамысловатый процесс, завершающий общую фоновую картинку (и избавляющий от необходимости использовать большое фоновое изображение):

$('.star1, .star2').remove(); // Перед созданием новых звезд, удаляем старые
for (var i = 1; i <= 50; i++) { // рисум 50 звезд одного и второго типа
	var top_st = Math.floor(Math.random() * (max_h/2)); // не ниже чем центр экрана
	var left_st = Math.floor(Math.random() * (max_w - 2)); // не доходя 2px до конца
	$('body').append('<div class="star2" style="top:' + top_st + 'px; left:' + left_st + 'px;"></div>'); // Рисуем звезды

	var top_st = Math.floor(Math.random() * (max_h/1.8)); // Чуть ниже центра экрана
	var left_st = Math.floor(Math.random() * (max_w - 2));
	$('body').append('<div class="star1" style="top:' + top_st + 'px; left:' + left_st + 'px;"></div>');	
}

Используются 2 типа звезд – маленькие (1x1) и большие(2x2), отображение которых прописано в CSS.


А теперь, пожалуй, приступим к тому, ради чего и писалась эта статья – реализация переходов между страницами.
Для скроллинга страниц вверх и вниз была применена следующая структура:

схема

В блок #home_screen при первоначальной загрузке сайта грузится mainbody (см. первоначальная загрузка), при переходе на другую страницу, происходит:

  1. загрузка данных в блок .down_page
  2. скроллинг на .down_page и очистка #home_screen
  3. сразу после этого класс .down_page меняется на .curent
  4. создается новый пустой блок с классом .down_page (см. после перехода).


При каждом последующем переходе блок .curent (старый) удаляется, а блок .down_page (старый) становится .curent, и создается новый пустой блок .down_page. (исключением является переход на главную страницу, когда страница скроллится вверх и структура приходит к виду «первоначальной загрузки»).
Если родительским объектом для всех 3х «экранов» является body, то появляется возможность скролить страницы при щелчке на колесико мышки. Это легко исправляется, если их поместить в другой блок (в моем случае в блок c id #window).

При реализации переходов между страницами необходимо было сделать так, чтобы корректный переход между страницами происходил независимо от типа перехода (ajax или нет), причем без изменений url и без добавлений дополнений параметров (типа &no_html=1 ). Для этого мы добавим в AJAX запрос, заголовок, сигнализирующий о том, что это запрос контента без шаблона. Внесем маленькие изменения в index.php (что лежит в корне), добавив в самое начало:

if (isset($_SERVER['HTTP_AJAX']))
	$_REQUEST['tmpl'] = 'component';

Тогда сам AJAX запрос примет вид:

$.ajax({
    url: page_url, //адрес запрашиваемой страницы
    dataType: 'html', // Тип возвращаемых данных
    beforeSend: function(xhr){
        xhr.setRequestHeader('AJAX', 'true'); // Устанавливаем заголовок AJAX в true
    },
    success: function(){ //функция, вызываемая при успешном запросе данных
    }
});

Также довольно интересным, на мой взгляд, является динамическая смена урла без перезагрузки страницы, но, к сожалению, это привилегия лишь браузеров с поддержкой HTML5, и реализуется за счет History API.

Для добавления элементов истории можно использовать

history.pushState([state object],[title],[URL])

state object — переменная состояния.
title — заголовок ссылки в истории.
URL —сам адрес, который будет отображаться в адресной строке.
Однако перед тем как выполнить данную функцию следует проверить, поддерживает ли это браузер:

support_replace_url = window.history && window.history.pushState && window.history.replaceState
&& !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)

if(support_replace_url)


Full Ajax, на сайте, если обобщить можно реализовать следующим образом:

  1. отключить mootools
  2. добавить в шаблон загрузку jQuery
  3. внести изменения в index.php, как указано выше.
  4. добавить на страницу следующий код:
$(document).ready(function(){
	$('a').click(function(){ // Все ссылки сделаем ajax
		load_page($(this)); // Вызываем функцию загрузки страницы (см ниже), и как параметр передаем саму ссылку
		return false; 
	})

	$("#ajax_block").ajaxStart(function(){ // Дейстрие при начале AJAX запроса
		$("#loading").show(); // Показываем блок загрузки (прогресс бар, как вариант)
	});
	$("#ajax_block").ajaxStop(function(){ // Действие при окончании AJAX запроса
		$("#loading").hide(); // Скрываем блок загрузки
	});
})

support_replace_url = window.history && window.history.pushState && window.history.replaceState // проверяем поддержку history API
  && !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)

function load_page(param, link){ // Сама функция запроса
	if (!link) // если второй параметр пуст (загрузка по клику на ссылку)
		href = $(param).attr('href'); // загружаем страницу указанную в параметре href ссылки
	else // иначе
		href = link; // грузим страницу указанную во 2_ом параметре (для возврата назад)
	wasajax = true;	// Был AJAX запрос
	$.ajax({ // сам запрос
		url: href,
		dataType: 'html',
		beforeSend: function(xhr){
			xhr.setRequestHeader('AJAX', 'true');
		},
		success: function(data){
			$('#ajax_block').html(data); // загружаем данные в блок #ajax_block
			if((jQuery.browser.msie && jQuery.browser.version > 9) || !(jQuery.browser.msie)){ 	// Если это не IE, 
				$('title').text( $(data).filter('title').text() );	// то меняем заголовок страницы
			}
			if(support_replace_url && !link){ // Если history поддерживается, и это не возврат назад(вперед)
				history.pushState(null, $(data).filter('title').text(), patt(href)); //то меняем URL в адресной строке	
			}		
		}
	});
}

$(window).bind('popstate', function(event){ // Действие кнопок вперед\назад
	if (wasajax) // Если запрос AJAX уже был осуществлен
		load_page(0, location.href); // загружаем посредством AJAX страницу из истории
	
})


И теперь последний момент о котором хотелось бы рассказать – интеграция с виджетами ВКонтакте.
Если AJAX не используется, их добавление не составляет никаких проблем – можно просто скопировать и вставить код с http://vkontakte.ru/developers.php#devstep2.
Однако, если сайт представляет собой одностраничное AJAX приложение, все становится несколько сложнее: для начала, каждый материал должен иметь свои собственные комментарии и свои собственные «лайки». Также необходимо поместить нужную информации при «расшаривании» материала (рассказать друзьям). Изучение их API позволило написать простенькую функцию:

$('iframe').remove(); // Удаляем старый блок лайков (если используются iframe, то селектор нужен более конкретный)
VK.Widgets.Like("vk_like", {type: "button", 
	pageDescription: "What kind of the end of humanity do you prefer?", // Описание (может динамически запрашиваться со страницы)
	text: 'What kind of the end of humanity do you prefer?', // Текст, отображаемый на страницы ВК
	pageUrl: 'http://the-end.info'+href, // URL страницы (должен быть абсолютным)
	pageTitle: $('.title_text:last').text(),  // Заголовок страницы
	pageImage: 'http://the-end.info'+$('.image_list img:last').attr('src'),  // Адрес изображения страницы (также абсолютный)
}, num($('.title').text()) );

Где num($('.title').text()) определяет номер (возвращает целочисленное значение) текущей страницы (в моем случае их всего 14, как вариант можно передавать сюда id материала или itemId) Необходимо отметить, что для одной страницы эти параметры должны быть различны для «лайков» и комментариев. И еще один момент, о котором стоит помнить – данные, передаваемые «ВКонтакту» для каждой страницы, кешируются. Если вы укажите одно описание страницы, нажмете «рассказать друзьям», затем описание измените и нажмете еще разок «рассказать друзьям» — вы увидите старое описание. Дабы новое вступило в силу, необходимо изменить номер num($('.title').text()).

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