Пользователь
0,0
рейтинг
16 сентября 2011 в 13:40

Разработка → Загрузка страницы с помощью Ajax как ВКонтакте из песочницы

Не так давно я задался вопросом, как же можно сделать так, чтобы страницы загружались с помощью ajax скрипта, как вконтакте и при этом были проиндексированы поисковыми машинами.

Данный скрипт я сделал на основе JS фреймворка jQuery (перейти на сайт) и плагина HashChange (перейти на страницу плагина).

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

Подключение скриптов:
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/hashchange.js"></script>


Функция:
	$jQuery = jQuery.noConflict();
	$jQuery(window).hashchange(function(){
		var link = window.location.hash.replace("#", "");
		get_page_by_hash(link);
	});


Данная функция вызывает функцию «get_page_by_hash» при изменении хэша страницы, первым аргументом которой будет являться ссылка на страницу.

Вторым шагом я сделал саму функцию «get_page_by_hash»:

 function get_page_by_hash(link){
	if(typeof(link) != "undefined"){
		if(link != ""){
			$jQuery.ajax({
				type: "POST",
				cache: false,
				async: false,
				url: link,
				success: function(data){
					if(data != ""){
						$jQuery("body").html(data);
					}
				}
			});
		}
	}
 }


В данной функции происходит замена html в тебе body на html, который пришел в ответе на запрос.
1. Метод передачи данных — POST нужен для определения того зашли просто на страницу или это запрос через ajax. Это позволит в шаблоне сделать условие, которое будет скрывать данные не требующие отображения при запросе скриптом:

if($_SERVER["REQUEST_METHOD"] == "GET"){ } 


Так же с помощью этого метода можно сделать замену html не в теге а внутри любого элемента, которого можно выбрать с помощью jQuery, при этом обрезать все не нужное в шаблоне с помощью условия, указанного выше.

Следующим шагом было выставление хеша страницы который мы отслеживаем с помощью функции выше:

$jQuery("a").click(function(){
	if($jQuery(this).attr("href").substr(0, 1) == "/"){
		window.location.hash = $jQuery(this).attr("href");
	}
});


Данная функция позволяет добавить hash в адресную строку браузера, работает во всех браузерах.

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

1. Нужно определить браузер с помощью этой функции:

function getNameBrouser() {
	var userAgent = navigator.userAgent.toLowerCase();
	// Определим Internet Explorer
	if (userAgent.indexOf("msie") != -1 && userAgent.indexOf("opera") == -1 && userAgent.indexOf("webtv") == -1) {
		return "msie";
 	}
 	// Opera
 	if (userAgent.indexOf("opera") != -1) {
 		return "opera";
	}
 	// Gecko = Mozilla + Firefox + Netscape
	if (userAgent.indexOf("gecko") != -1) {
 		return "gecko";
	}
	// Safari, используется в MAC OS
	if (userAgent.indexOf("safari") != -1) {
 		return "safari";
	}
	// Konqueror, используется в UNIX-системах
	if (userAgent.indexOf("konqueror") != -1) {
 		return "konqueror";
	}
	return "unknown";
}


2. Теперь нам нужно расширить функцию обновления hash страницы:
$jQuery("a").click(function(){
	if($jQuery(this).attr("href").substr(0, 1) == "/"){
		if(getNameBrouser() == "gecko"){
			window.history.pushState("", "", $jQuery(this).attr("href")); 
			window.history.replaceState("", "", $jQuery(this).attr("href"));
			get_page_by_hash($jQuery(this).attr("href"));
		}else{
			window.location.hash = $jQuery(this).attr("href");
		}
		return false;
	}
 });


С помощью данных скриптов у Вас будет сайт похож (по переходам по страницам) на сайт вконтакте.ру
Сергей @koksharov
карма
1,0
рейтинг 0,0

Похожие публикации

Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (41)

  • +10
    [зануда]Скажите, а при чем тут ВК? Вы других сайтов с аякс навигацией не используете? [/зануда]
  • 0
  • +5
    Думаю определение History API намного легче было бы, если вместо:
    function getNameBrouser() {
     var userAgent = navigator.userAgent.toLowerCase();
     // Определим Internet Explorer
     //...весь остальной код
     return "unknown";
    }
    

    и
    $jQuery("a").click(function(){
      if($jQuery(this).attr("href").substr(0, 1) == "/"){
       if(getNameBrouser() == "gecko"){
        window.history.pushState("", "", $jQuery(this).attr("href")); 
        window.history.replaceState("", "", $jQuery(this).attr("href"));
        get_page_by_hash($jQuery(this).attr("href"));
       }else{
        window.location.hash = $jQuery(this).attr("href");
       }
      }
     });
    


    написать просто:
    function has_history_api() {
      return !!(window.history && history.pushState);
    }
    
    $jQuery("a").click(function(){
      if($jQuery(this).attr("href").substr(0, 1) == "/"){
       if(has_history_api()){
        window.history.pushState("", "", $jQuery(this).attr("href")); 
        window.history.replaceState("", "", $jQuery(this).attr("href"));
        get_page_by_hash($jQuery(this).attr("href"));
       }else{
        window.location.hash = $jQuery(this).attr("href");
       }
      }
     });
    
    • +3
      и вообще — так:
      jQuery("a").click(function(){
         var href = jQuery(this).attr("href");
         if( href.indexOf('/') != 0 ) return;
      
         if ( window.history && history.pushState ) {
           history.pushState   ("", "", href); 
           history.replaceState("", "", href);
           get_page_by_hash(href);
         } else {
           location.hash = href;
         }
       });
      
      • +1
        тогда еще короче:
        $("a").click(function(){
           var href = $(this).attr("href");
           if( href.indexOf('/') != 0 ) return;
        
           if ( window.history && history.pushState ) {
             history.pushState   ("", "", href); 
             history.replaceState("", "", href);
             get_page_by_hash(href);
           } else {
             location.hash = href;
           }
         });
        

        экономия 12 байт :)
        • +1
          Для плагина не очень подходит, т.к. в плагинах желательно использовать длинное названия.
          • +2
            Так ведь же можно делать так:

            (function( $ ){
            $.fn.myPlugin = function() {
            // Do your awesome plugin stuff here

            };
            })( jQuery );
  • +3
    Для этой цели есть библиотека pjax (https://github.com/imsamurai/jquery-pjax). И скоро мы со ckald сделаем демо-страничку с подробным описанием всех возможностей. Там есть и pushState и hash navigation.
    • +1
      • +2
        О, просмотрел, что ты уже :). Удваиваю наш pjax – безукоризенно отработал на всеукраинском медиаконкурсе с mp3-плеером
  • +4
    Надо же было ссылку на демо вставить!
    • –1
      Ссылку на вконтакте?:)
  • +3
    Лучше проверять на AJAX в скрипте не по методу запроса, а через заголовки.
  • +6
    Имхо:

    1. Браузер лучше определять через фичдетект, а не по user-agent.
    2. AJAX-запрос определять по заголовку, а не методу
    3. Использовать live вместо click
    4. Обернуть всё в $jQuery(function() { });
    5. "!==" вместо "!="; "===" вместо "=="
    6. Закэшировать $jQuery(this).attr('href')
    7. Browser :)

    Как-то так
    • 0
      8. Из комментария ниже — добавить return false; в обработчик клика
      • +1
        или e.preventDefault();
  • 0
    Подобную штуку я делал в одной из админок:
    1. Перехватываем все ссылки и делаем запрос к серверу:
     $("a").click(function()
    {
      $.ajax({
      data:{'isajax':true;}
      url:$(this).attr('href');
      success:function(data){
        
        $("#container").html(data);
      }
      });
    });
    

    2. Со стороны сервера проверяем наличие заголовка $_SERVER['HTTP_X_REQUESTED_WITH']) (PHP), либо POST переменной isajax, если так оно и есть, то меняет переменную шаблона.

    3. Если нужно передать скрипты тогда в шаблоне через какой-нибудь спецсимвол выводим список скриптов, парсим при событии success, подключаем их после добавления html к телу документа.
    • 0
      Простите забыл добавить

      return false;


      В конце обработчика клика по ссылке…
  • +1
    я не увидел, гарантию того, что это всё проиндексируется поисковиками.
    Google то может быть, а остальные?
    • 0
      все ссылки стоят не #/url/to/page а /url/to/page а т.к. поисковые роботы не используют javascript они нормально индексируют сайт
      • +3
        А как же поведенческие факторы? Поисовик увидит, что пользователь был на одной странице, хотя пользователь мог десяток страниц просмотреть.
        • 0
          Поясните, пожалуйста, этот момент.
          • 0
            Поисковик видит, что на главной странице сайта есть ссылки на внутренние. А также видит, что по ним никто не переходит. По этому поведенческому фактору он может значительно понизить вес, передаваемый ссылками главной на внутренние.

            Можно еще много различных логичных предположений сделать, но все сводится к тому, что поисковики учитывают поведение пользователя на сайте, в том числе и переходы по внутренним ссылкам, которых в такой реализации просто не будет.
            • 0
              Подождите… А как поисковик видит, что кто-то делает переход по ссылкам на сайте? Разве связь между поисковиком и сайтом не разрывается в тот момент, когда осуществляется переход из поисковой выдачи на конкретную страницу?
              • 0
                даже если есть аналитика, поисковики видят что был переход со страницы на страницу, т.к. загружается скрипт аналитики
                • +1
                  Мм… Вернее – если есть/подключена аналитика. Тогда это все объясняет. Согласен. Спасибо.
                  • 0
                    Есть еще тулбары, а также хитрый хром, собирающий нужную гуглу информацию.
  • +1
    А демо есть?
  • 0
    дописал сегодня что то подобное, только с кэшированием данных на указанное время, загрузкой данных в указанные блоки и всякими плюшками
  • +1
    пользуюсь jquery-pjax + django-pjax
  • 0
    все татары кроме я, getNameBrouser(), getNameBrowser()
  • 0
    jquery (да и другие библиотеки) для ajax добавляют свой ключ, по нему и нужно определять. не по get-post
    function isAjax ()
    {
    if (
    isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == «XMLHttpRequest») return true;
    return false;
    }
  • +1
    Зачем строка $jQuery = jQuery.noConflict();, когда уже есть глобальная переменная jQuery? Тупняк — лишняя переменная, лишний байт, смысла ноль.

    Последние версии jquery давно умеют $(window).bind('hashchange') без всяких плагинов.

    По getNameBrouser() уже прошлись выше.

    Вцелом, очень низкого качества код.
    • +1
      Еще, кстати, очень раздражает, когда в одном коде рядом используюется и camelCase и under_score. Создается впечатление, что автор накопипастил из разных мест, а сам программировать не умеет.
      • 0
        есть целое направление программистов конуструкторов кода, которые просто методом тыка\копипаста действуют. программить вообще не умеют а чистый копипаст. как кубики лего складывают из кусков разного кода.
  • +1
    нужно вешать событие на live, чтобы ссылки в подгружаемом контенте тоже были аяксовыми
    jQuery(«a»).live('click', function(){… })
  • 0
    Все уже давно придумано в нескольких интерпретациях. Главный минус использовать от использования хештега — вам до конца жизни нужно будет тащить страницу с яваскриптом на ней, чтобы показывать контент юзерам. Этих недостатки полностью исключает History API. Именно в комбинации и нужно использовать оба способа — там где уже возможно pushState, там где это не возможно(привет олдскул браузеры) — юзать хештег. Указанная мною выше библиотека сама понимает, когда нужно использовать какой способ подмены адреса браузера.
  • 0
    Тащить весь html не целесообразно, значительно быстрее запрашивать только данные, отрисовывать и кэшировать их на стороне клиента. На эту проблему натолкнулись разработчики мобильного приложения html5 facebook, после чего заявили что native намного шустрее. На что им намекнули создатели ExtJs
    www.theregister.co.uk/2012/09/14/facebook_html_5_vs_native_apps/
    www.sencha.com/blog/the-making-of-fastbook-an-html5-love-story

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