Меню

Техники за напреднали

Влез Излез

Deep Linking – част 1

В последните два урока представихме как можем да добавим AJAX презареждане на страниците в нашия сайт включително и с кеширане на информацията. Естественият ход на развитие на един сайт, а и коментари към уроците, предполагат да добавим и deep linking.

Deep Linking

Нека първо обясним какво е deep linking. Ако отворите страниците от предния път (може и демото на сайта: http://magadanski.com/demo/ajax-requests/) и разцъкате навигацията ще видите, че макар и съдържанието да се променя, адреса на страницата остава все един и същ. Това може да се окаже проблем, когато искаме да дадем link на някой приятел за точно определена страница.

Deep linking е иманно възможността да представяме различни състояния на един и същ URL. Използва се когато дадена страница променя съдържанието си посредством JavaScript. Използвайки именно още JS можем (и дори трябва) да обработим допълнително подадена информация в URL-а на страницата, за да заредим същото това състояние, до което човек е достигнал кликвайки на бутон или нещо друго.

Deep linking може да се наложи при lightbox-ове, табове, акордеони, цели страници заредени с AJAX (както е в нашия случай) и др. Тъй като за момента при нас е налице единствено зареждане на ново съдържание с AJAX ще се погрижим за този случай (а в последствие ще добавим и останалите елементи, за да видим как най-добре можем да ги съчетаем).

Техники за deep linking

Съществуват различни методи за подаване на допълнителна информация към script-овете на страницата през URL. Най-често се срещат стандартни GET аргументи, които могат лесно да се използват и от сървъра, в случай че страницата ни се генерира от някакъв server-side script или чрез URL hash-ове.

URL GET аргументи

Това са незадължителни двойки ключ-стойност, които се изреждат след основната част на URL-а. След ключа се изписва знак за равенство, а след това е самата стойност. Преди да се подадат към URL-а се добавя „?“ за да ги отдели. Двойките ключ-стойност се отделят с амперсанд (&). Пример:

http://example.com/?arg1=val1&arg2=val2

URL hash

След GET аргументите в един URL идва ред на (отново незадължителен) URL hash. Отделя се чрез диез (#). Стойността на hash-а се третира като една цяла стойност. Може да се достъпи в JavaScript използвайки window.location.hash. Най-често се очаква, че това е просто една единствена стойност, която трябва да се обработи по определен начин. Разбира се, нищо не ни пречи да добавим някакви наши разделения, които когато обработим по правилен начин, да ни предоставят по-богата информация.

Трябва да се отбележи, че в IE 7/8 съществува бъг, който в някои случаи би довел до презареждане на страницата при задаване на нова стойност за hash-а на URL-а.

history.pushState

HTML5 hostory API-то на JavaScript дава възможност изцяло да променим адреса, който браузъра показва без да презареждаме страницата. Още по-хубавата част е, че новият адрес просто се добавя в историята на браузъра, така че лесно можем да цъкнем на back (а после и на forward) бутона на браузъра и ще идем до правилния URL. В нашия случай, в който просто зареждаме съдържанието на нова страница, която има собствен URL, това е най-доброто решение, защото можем просто да зададем новия адрес.

Най-големият минус тук е, че по този начин губим поддръжка за стари браузъри (IE 7/8/9).

jQuery Address

За наш огромен късмет, не сме първите, които биха искали да добавят deep linking в сайта си. Даже мнозинстото искат тази функционалност. Благодарение на това съществуват различни JS библиотеки, които да ни улеснят като се грижат за проблеми в различните браузъри. jQuery Adress ни дава и възможност да използваме history.pushState като основен метод за работа, като с минимални усилия можем да добавим и поддръжка за IE 7/8 чрез hash-ове.

Защо точно jQuery Address

Поради няколко причини:

  1. Защото това е jQuery plugin, а ние работим с jQuery
  2. Защото е разработен от същия човек, който на времето е направил SWF Address.

Какво е SWF Address?

Това е най-старата (известна на мене) JavaScript библиотека, която се използваше за подобна функционалност. Датира доста преди HTML5 и HTML web приложенията. Името може би ви подсказва, че тази библиотека даваше възможност за комуникация със SWF файлове (flash), така че SWF Address беше единственият начин Flash web приложенията да дават връзки към различните си състояния.

Да отдадем почит на човека разработил SWF Address и jQuery Address – Ростислав Христов (да – българин е)!

Добавяне на deep linking функционалност

Ще работим с файловете от урока AJAX заявки (без кеширането). Защо без кеширане? Защото кеширането не е задължителен елемент, а колкото и да е опростено допринася някаква слъжност към кода, а в случая се опитваме да поддържаме всичко максимално просто. Така ще имате възможност да се упражните и самички и да добавите deep linking към версията с кеширане.

Ето и архив на файловете, с които ще започнем работа.

Като за начало, нека изтеглим jQuery Address JS plugin-а. Можете да направите това от официалната страница: http://www.asual.com/jquery/address/.

Можете да работите и с dev версията. Това е най-новата версия. Толкова нова, че е още в процес на разработка и е възможно да се окаже, че има bug-ове. Даже докато писах уроке опитах и с нея, но резултатът не беше толкова добър, колкото със стабилната версия 1.5.

Dev версията може да се вземе от GitHub (папка src).

След като вече сме изтеглили jQuery Address (аз го записах в js/jquery-address) трябва да го добавим в страниците си:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>AJAX Requests</title>
	<link href="http://fonts.googleapis.com/css?family=Open+Sans:300&amp;subset=latin,cyrillic-ext,cyrillic" rel="stylesheet" type="text/css" />
	<link rel="stylesheet" type="text/css" href="style.css" />
	
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
	<script type="text/javascript" src="js/jquery-address/jquery.address-1.5.js"></script>
	
	<script type="text/javascript" src="js/func.js"></script>
</head>

Не забравяйте, че това трябва да е налице във всички страници (index.html, slider.html, accordion.html, tabs.html).

Сега вече можем да започнем работа и по същинската интеграция на jQuery Address.

Като за начало нека инициализираме jQuery Address за линковете от основната навигация и нека закометираме останалия ни код, къй като той ще се изпълнява при по-различни обстоятелства.

jQuery(function ($) {
	$.address.init(function () {
		$('nav a').address();
	})
	
	// $(document).on('click', 'nav a', function (e) {
	// 	e.preventDefault();
		
	// 	$.get($(this).attr('href'), function (data, status, XHR) {
	// 		if (status == 'success') {
	// 			$('section[role="e;main"e;]').html($(data).find('section[role="e;main"e;]').html());
				
	// 			$('title').html($(data).filter('title').html());
	// 			$('header').html($(data).find('header').html());
	// 		} else {
	// 			// tell the user we could not connect to the server
	// 		}
	// 	});
	// });
});

Ако тестваме резултатът сега, ще видим, че jQuery Address използва hash-ове, за да обозначи на коя страница сме. За момента съдържанието от новите струници, обаче не се зарежда. Ще стигнем и до там.

jQuery(function ($) {
	$.address.init(function () {
		$('nav a').address();
	});
	
	$.address.change(function (e) {
	});
});

Добавяме address.change event handler, който ще зарежда информацията, когато адресът на браузъра се промени.

jQuery(function ($) {
	var root = '/tutorials/deep-linking';
	
	$.address.init(function () {
		$('nav a').address();
	});
	
	$.address.change(function (e) {
		$.get(root + $.address.value(), function (data, status) {
			if (status == 'success') {
				// handle loaded data
			} else {
				// tell the user we could not connect to the server
			}
		});
	});
});

Добавили сме променливата root, в която ще съхраняваме root URL-а на сайта. В случай, че сайтът ни се намира в основата на домейна – тогава няма да имаме нужда от тази променлива. Но тъй като аз работя в папка „tutorials/deep-linking“ е нужно да използвам такава променлива, която да ми помогне при правилното построяване на адресите, от които да зареждам съдържание.

Остава само да обработим по правилен начин заредената информация:

$.address.change(function (e) {
	$.get(root + $.address.value(), function (data, status, XHR) {
		if (status == 'success') {
			$('section[role="main"]').html($(data).find('section[role="main"]').html());
			
			$('title').html($(data).filter('title').html());
			$('header').html($(data).find('header').html());
		} else {
			// tell the user we could not connect to the server
		}
	});
});

До тук всичко върви на Chrome, Firefox, Safari, Opera, Internet Explorer 10, 9 и 8. Ами IE7? Оказа се, че начина, по който jQuery Address добавя hash за IE7 е като включва пълен адрес, а не само на компонента от връзката, която сме добавили. Този проблем има 4 решения:

  1. Да променим връзките, така че да са абсолютни, а не релативни
  2. Да променим връзките, така че да са релативни, но според site root
  3. Да добавим няколко реда JS, в който да правим проверка за IE7 и в такъв случай да прескочим конкатенирането с променливата root
  4. Да drop-им support за IE7

Аз лично предпочитам последния вариант. Пазарният дял на IE7 е под 2%. Освен това IE7 е четвъртата версия та IE от най-новата назад. Google официално поддържат само последните 2 major версии на всички браузъри (значи официално не поддържат дори IE8).

Какво стана с history.pushState()?

Този урок стана вече твърде дълъг, така че това ще го оставим за следващия път. Тогава ще добавя и demo на целия урок.

Ако съм в добро настроение даже може да оправим и IE7.

  • Devseon каза:

    Урокът започва добре. За back бутона е важно да се обяснят нещата, особено в IE. Ще пиша повече, когато целият урок е завършен. Харесва ми това, че си разгледал deep linking, определено важен topic. Модерно е да се правят Full AJAX сайтове, но в много случаи deep linking не се включва, което е сериозен пропуск.

    PS Защо линковете в коментарите са nofollow :)?

    • magadanski_uchen каза:

      Личи си колко правиш уроците и колко пишеш for the pass the time :P. Deep Linking е налице, както и поддръжка за Back бутона на браузърите. Когато напиша и втора част от урока ще кача и demo, където ще можеш сам да провериш, че всичко работи.

      Единственият проблем в момента е с IE7, но за него съм писал в урока.

      P.S. nofollow в коментарите е заради спамъри като тебе 😛 (по default е така в WordPress – би трябвало да знаеш тези SEO особености на един от най-използваните CMS-и).

  • Devseon каза:

    Ще се радвам да видя демото. Аз не „правя“ уроците, защото знам как се правят повечето неща, макар и по друг начин (без jQuery Address). Въпреки това, чета уроците. Така се уча да гледам нещата от друг ъгъл, забелязвам интересни подробности. Ето нещо, което може да ти бъде интересно: https://developers.google.com/webmasters/ajax-crawling/docs/getting-started?hl=bg . Според мен IE много объркват нещата с тяхната назадничавост. history.pushState() е пътят, не #! и после сървърни обработки на _escaped_fragment_ .

    P.S. Хехе, знам :D… въпросът ми по-скоро се превежда: „Хайде pls да не са nofollow вече линковете“.

    • magadanski_uchen каза:

      Не „правиш“ уроците, ама затова после пишеш глупости, че нямало Deep Linking, при положение, че има.

      Не че е задължително да се ползва jQuery Address, но в практиката съм стигнал до извода, че е много по-добре (за някои неща) да използваш plugin, който не е от вчера и е тестван много повече от нещо, което ще скалъпиш за 10-15 минути.

      Това за #! и _escaped_fragment_ честно казано за първи път го виждам. От една страна – има логика, но от друга – съществува ли изобщо някой, който да си даде толкова много зор? По-скоро ще направя цял нов сайт, отколкото да добавя поддръжка за подобно нещо.

      Относно history.pushState() – определено е по-доброто решение, когато става въпрок за зареждане на съдържание на нова страница, но в някои случаи може просто да искаш да покажеш състояние на текущата страница, което ако покажеш с отделен URL ще има отрицателно влияние, тъй като такава страница или няма да съществува или ще представя нещо друго, а не състоянието, в което си бил по-рано.

      P.S. Мечтай 😛 (http://www.youtube.com/watch?v=txlXcJDtDwM)

  • Devseon каза:

    Прав си, че е играчка. На теория трябва в един AJAX сайт, който използва # , заради google crawler-ите винаги да е #! и после проверки в сървърната част за _escaped_fragment_ и да се върне HTML snapshot. Много сайтове го ползват. Twitter примерно. Аз лично харесвам как си направил нещата в този tutorial. Имаме реални html страници, които могат да се отворят директно, hash-а може да се наложи да се използва само в IE, тъй като history.pushState() ще свърши необходимото за смяна на адреса на истинската страница. Реалният шанс в сайт като твоя crawler-ите да се докопат до link с # в него е само ако някой IE user реши да постне url-а си от address bar-a в някой външен сайт (backlink към твоя). Тази вероятност не е никак голяма, пък и не трябва да те бърка, след като си има директни линкове към истинските страници. Така че нещата са добре откъм SEO.

Вашият коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax