AJAX и history API
Сегодня я решил написать статью про ajax и history API вместе, так как history API без него просто не имеет смысла. Мы напишем универсальную функцию ajax() и модифицированную из прошлой моей статьи функцию go().
Итак, начнем!
Чтобы использовать AJAX нужно создать на странице обьект XmlHttpRequest.
Кроссбраузерно это делается так:
function XmlHttp(){
var xmlhttp;
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");}
catch (E) {xmlhttp = false;}
}
if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
}
И еще одна вспомогательная функция для передачи POST данных
function ajaxDataMaker(data){
if(typeof data!="object")return;
var result="",a=0,c=0;
for (var i in data)a++;
for (var i in data){c++;result+= i+"="+data[i]+(c!=a?"&":'')}
return result;
}
Отлично, это мы сделали!
Теперь перейдем к написанию самой функции ajax() :
function ajax(param){//method,url,data,success
var req = new XmlHttp();
var method=(!param.method ? "POST" : param.method.toUpperCase());
var send=(method=="GET"?null:(param.data?ajaxDataMaker(param.data):null));
req.open(method, param.url, true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send(send);
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200) {//если ответ положительный
if(param.success) param.success(req.responseText);
}
}
}
Теперь разберемся, что же тут происходит?
В первой строке функции мы создаем тот самый XMLHttpRequest объект, о котором описано выше:
var req = new XmlHttp();
Далее у нас идет определения типа запроса - GET или POST :
method=(!param.method ? "POST" : param.method.toUpperCase());
Как видите, по умолчанию у меня стоит POST (мне он почему-то больше нравится), вы можете поставить GET, если хотите.
В следующих строках идет подготовка данных для передачи в зависимости от типа запроса:
var send=(method=="GET"?null:(param.data?ajaxDataMaker(param.data):null));
Если мы используем GET запрос, то мы передаем данные прямо через адресную строку и запрос посылаем пустым.
Если у нас тип запроса - POST, мы используем вспомогательную функцию, данную выше.
С этим вроде все.
В следующем шаге мы открываем соединение:
req.open(method, param.url, true);
Отправляем заголовки:
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Если честно, для чего служит первый заголовок не знаю сам, но без него ничего не работает.
А вот второй заголовок нужен серверу, чтобы отличить AJAX запрос от обыкновенного. На PHP это проверяется так:
$ajax=$_SERVER['HTTP_X_REQUESTED_WITH']=="XMLHttpRequest"?true:false;
$ajax здесь будет равна true если запрос AJAX, иначе false.
Дальше посылаем запрос:
req.send(send);
Следующим шагом будет долгожданное завершение запроса:
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200)
if(param.success) param.success(req.responseText);
}
ajax({
url:"site.ru/ya.php?act=msg", //думаю, в комментариях не нуждается
method:"POST",//указываем метод. Он и так по умолчанию POST, но это для наглядности
data:{name:"ВАСЯ",id:453,msg:document.getElementById("msg).value},//передаются данные.
success:function(data){document.getElementById('success').innerHTML=data;}
})
В параметре url у нас пишется адрес. Даже если метод POST, все равно можно писать GET запрос.
В data передаются данные. На сервер они придут с такими же именами, как и здесь, то-есть:
$_POST['name']=="ВАСЯ";
$_POST['id']==453;
$_POST['msg']=="значение текстового поля с id='msg'";
И, наконец, success. Сюда передается функция с параметром, в котором содержится ответ от сервера, вы можете назвать его как угодно. То-есть если вы написали:
success:function(server_callback){.....}
То в server_callback будет ответ от сервера.
Теперь перейдем к history API.
Такая штука поддерживается в Google Chrome и начиная с версии 3.6 Mozilla FireFox.
С помощью API можно отслеживать щелчки на кнопки <вперед> <назад> в браузере (от кнопки <обновить> не спасает) и изменять адресную строку не используя хэш,что есть хорошо.
Начнем с изменения адресной строки.За это отвечает функция history.pushState().
Так как поддерживается не везде, нам надо знать, можно ее использовать или нет. Для этого введем переменную:
var histAPI=!!(window.history && history.pushState);
Она принимает значение true если поддерживается History API, иначе - false.
Теперь давайте напишем саму функцию.
function go(param,event,success) {
var url,success=success||param.success||false,event=event||param.event||false;
if(typeof param.href!="undefined")url=param.href;
else {url=(typeof param=="string"?param:(typeof param.url=="object" ? param.url.href : param.url));}
if(!histAPI){window.location=url;return true;}
if(event && event.button==1)return true;
ajax({
url:(typeof param.data!="undefined" ? url+"&"+param.data : url),
method:"GET",
data:param.data,
success:function(data){
history.pushState(null,null, url);
}
})
return false;
}
<a href="index.php" onclick="return go(this,event,function(data){alert(data)})">Главная</a>
function popstate(url) {
ajax({
url:url,
method:"GET",
success:function(data){
//Ну, здесь пишете что надо делать с полученными данными
// например так
document.getElementById("content").innerHTML=data;
}
})
}
Здесь, все немного по-другому. Надо вешать обработчик на событие popstate объекта window. Делается это так:
window.onload=function(){
if (histAPI) {
window.setTimeout(function() {
window.addEventListener("popstate",
function() {
popstate(location.pathname);
},
false);
}, 1);
}
}
При загрузке страницы, если поддерживается history API, к навигационным кнопкам привязывается функция popstate.
Если событие popstate не ловить, то адрес страницы будет просто меняться, а контент будет оставаться неизменным. Поэтому мы ловим это событие, и вызываем функцию, которая отправляет запрос по текущему адресу и вставляет данные в нужное место страницы.
Я объяснил все, что знал, спасибо за прочтение. Если вы заметили ошибку или у вас есть вопрос - напишите это пожалуйста.
И если уж не сложно, напишите комментарий, как понравилось, все-таки первая большая статья, интересно ваше мнение.
Сливаев Дмитрий.
|
Ошибочка в строке:
Нужно было указать:
Статья очень хорошая, как раз хотел почитать про History API.
Да, статья супер, всё расписано, но вот последние два скрипта я не понял, зачем это надо вообще? Если для управления кнопками, то ничего не происходит:(
Может есть у кого рабочий пример целиком?
Спасибо за статью. Удобно когда при переходах по ссылкам отрабатывает AJAX, но, при этом, у каждой страницы есть полноценный адрес. В качестве примера эффективного использования, этот механизм реализован ВКонтакте.
Здравствуйте!
По поводу AJAX-части статьи...
Я новичок. Подскажите пожалуйста, можно ли сделать следующее:
Мне нужно чтобы функция ajax(param) не только принимала мои параметры, но и сама возвращала request.responseText в мою пользовательскую функцию, из которой была вызвана, а не вызывать для этой цели еще одну пользовательскую функцию
То есть:
function my_func()
{
var result = ajax(param);
}
И в этой же функции делать с результатом все что необходимо.
Что-то типа:
сначала return request.responseText
в функции req.onreadystatechange = function()
и далее return полученного результата в функции ajax(param)
У меня никак это не получается... А хочется именно так
Заранее благодарен всем откликнувшимся.
JS - событийно ориентированный язык. На нём нельзя сделать так, как вы хотите)
функция Ajax ошибка в строке 11. Вот как я её исправил
ошибка нубы
functionv go(param)
исправте днища
Пример History API совершенно не понятный.
Вот живой пример без Ajax:
Не хочу вас обижать, но по-моему это немного бред.
Во первых
А вы уверены что у пользователя поддерживается history API ? Если он не поддерживается, все попытки пользователя щелкнуть на ссылку будут изначально обречены на неудачу.
Во вторых,
Кто-нибудь объяснит мне, зачем мы это делаем???
И это вопрос как от чайника
Что это вообще такое и для чего?
Спасибо!) Че то даже забыл про этот способ!)
На самом деле можно передать абсолютно любой заголовок.
"Синтаксис
void setRequestHeader(String имя, String значение)
Аргументы
имя
Имя устанавливаемого заголовка. Этот аргумент не должен содержать пробелы,
двоеточия, символы перевода строки или листа.
значение
Значение заголовка. Данный аргумент не должен содержать символы перевода
строки или листа."
Я это знал, но все равно спасибо за информацию. Просто такой заголовок шлет jQuery, и я решил не изобретать новый.
На мой взгляд не очень удобочитаемое форматирование кода, местами встречаются переменные с именами в духе a, b, c, что не способствует лучшему пониманию алгоритма. Пробелов явно не хватает между выражениями - всё сливаетсяводнустрокуитруднопонятьчтотам происходит. Думаю, что если бы комментарии/объяснения были прямо в коде, то это также повысило шанс разобраться в вопросе. В инете (да ине этом сайте) примеров навалом как лучше оформлять.
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.