Змініть URL-адресу в браузері, не завантажуючи нову сторінку за допомогою JavaScript


297

Як у мене буде дія JavaScript, яка може мати певні наслідки на поточній сторінці, але також змінити URL-адресу в браузері, тож якщо користувач натискає перезавантажити або закладку, то використовується нова URL-адреса?

Було б також непогано, якби кнопка "назад" перезавантажила початкову URL-адресу.

Я намагаюся записати стан JavaScript в URL.


1
Це було б так приємно. Звичайно, це буде обмежено модифікаціями з одним доменом. Але деякий контроль на шляху клієнта (а не лише хеш) - це логічний крок, коли перезавантаження сторінок є своєрідним "крайнім засобом" для багатьох додатків.
гарпо

1
pushStatefor(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);}
Корисне

Приклад цього ефекту в дії: dujour.com
Бен

2
Приклад цього ефекту: facebook.com (Під час відкриття зображень у лайтбоксі)

це гарне питання. однак, сумна ситуація в тому, що якби це питання було задано сьогодні таким чином, воно було б заперечене і стрибнуло на "це не той веб-сайт, на якому люди змушують писати весь ваш код".
роса

Відповіді:


118

За допомогою HTML 5 використовуйте history.pushStateфункцію . Як приклад:

<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
   history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>

і href:

<a href="#" id='click'>Click to change url to bar.html</a>

Якщо ви хочете змінити URL-адресу, не додаючи запис до списку кнопок назад, скористайтеся history.replaceStateнатомість.


Ти маєш рацію, востаннє експериментував із Chrome. Я тільки зараз спробував Firefox 3.6 на моєму Ubuntu, він не працював. Я думаю, нам доведеться почекати, поки HTML5 повністю підтримається у FF
clu3

15
Зразок коду вирізається та вставляється з developer.mozilla.org/en/DOM/Manipulating_the_browser_history . Що насправді турбує пояснення того, що в цьому випадку означають фу та бар.
mikemaccana

2
Футо і смуга нічого не означають, це довільно визначений стан об'єкта, який ви можете отримати пізніше.
Пол Діксон

3
@Paul: Так, ця стаття надає цю інформацію.
mikemaccana

2
ЯК розміщую цей коментар, він працює на Firefox Chrome і сафарі. Не пощастило з мобільним сафарі на ipad чи iphone :(
Sid

187

Якщо ви хочете працювати в браузерах , які не підтримують history.pushStateі history.popStateтим НЕ менш, «старий» спосіб встановити ідентифікатор фрагмента, який не викличе перезавантаження сторінки.

Основна ідея полягає у встановленні window.location.hashвластивості значенням, яке містить будь-яку інформацію про стан, яка вам потрібна, потім або використовуйте подію window.onhashchange , або для старих браузерів, які не підтримують onhashchange(IE <8, Firefox <3.6), періодично перевіряйте подивіться, чи змінився хеш ( setIntervalнаприклад, наприклад) та оновіть сторінку. Вам також потрібно буде перевірити значення хеша на завантаженні сторінки, щоб налаштувати початковий вміст.

Якщо ви використовуєте jQuery, є плагін хеш-змін, який використовуватиме той метод, який підтримує браузер. Я впевнений, що плагіни є і для інших бібліотек.

Слід бути обережним - зіткнення з ідентифікаторами на сторінці, оскільки браузер прокручує будь-який елемент із відповідним ідентифікатором.


2
Чи не пошукові системи ігнорують ці внутрішні посилання (хеші)? У моєму сценарії я хочу, щоб і павуки брали на себе ці посилання.
Дрю Ноакс

3
@Drew, наскільки я знаю, немає можливості пошукові системи трактувати частину сторінки як окремий результат.
Меттью Крамлі

8
Зараз є пропозиція змусити пошукові системи побачити хеши: googlewebmastercentral.blogspot.com/2009/10/…
LKM

5
Замість використання setIntervalдля інспекції document.location.hashможна використовувати hashchangeподію, оскільки вона набагато більше прийнята. Тут перевірте, які браузери підтримують кожен стандарт . Мій сучасний підхід - використовувати push / popState у браузерах, які його підтримують. На інших я встановлюю хеш і спостерігаю лише за hashchangeпідтримуваними браузерами. Це залишає IE <= 7 без підтримки історії, але з корисним постійним посиланням. Але хто піклується про IE <= 7 історію?
Irae Carvalho

2
@gabeDel Так, хоча я не думаю, що Analytics записує хеш, тому він буде мати однакову URL-адресу. Кращим способом було б вручну зателефонувати _trackPageviewза допомогою "реальної" URL-адреси нової сторінки.
Меттью Крамлі

37

window.location.href містить поточну URL-адресу. Ви можете читати з нього, ви можете додавати його, а також можете замінити, що може спричинити перезавантаження сторінки.

Якщо, як це здається, ви хочете записати стан javascript у URL-адресі, щоб він міг бути закладений у закладки, не перезавантажуючи сторінку, додайте її до поточної URL-адреси після # та має фрагмент javascript, ініційований подією завантаження, розібрати поточний URL-адреса, щоб побачити, чи містить він збережений стан.

Якщо ви використовуєте a? замість # ви змусите перезавантажити сторінку, але оскільки ви будете аналізувати збережений стан при завантаженні, це насправді не може бути проблемою; і це також призведе до коректної роботи кнопок вперед та назад.


2
Запис стану javascript в URL - саме те, що я намагаюся зробити
Стівен Ноубл,

21

Я б сильно підозрював, що це неможливо, оскільки це було б неймовірною проблемою безпеки, якби вона була. Наприклад, я міг би зробити сторінку, яка була схожа на сторінку входу в банк, і зробити URL-адресу в адресному рядку таким же, як у справжнього банку !

Можливо, якщо ви поясните, чому ви хочете це зробити, люди можуть запропонувати альтернативні підходи ...

[Редагувати в 2011 році: з того часу, як я написав цю відповідь у 2008 році, з'явилася більше інформації про техніку HTML5, яка дозволяє змінювати URL-адресу, поки вона з того самого походження]


6
Не так багато проблеми, якщо зміни, що не перезавантажувались, були обмежені до шляху, рядка запиту та фрагмента, тобто не авторитету (домену та іншого).
Оллі Сондерс

2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg - приклад того, що можливо, спробуйте переключити відео :)
Spidfire

Ви можете лише змінити location.hash (усе після #), як зазначає Метью Чумлі у прийнятій відповіді.
Пол Діксон

2
Ви використовуєте Facebook? Facebook змінює URL-адресу, не завантажуючи її, використовуючи history.pushState().
Дерек 朕 會 功夫

Пол Діксон, ви повинні помітити вхідні фейсбук, коли ви клацаєте на імена зліва, просто змінюється URL-адреса, і новий чат завантажується у вікно чату, сторінка не оновлюється. також є багато інших сайтів на WebGL, вони роблять те саме
Dheeraj Thedijje

8

Налаштування безпеки веб-переглядача заважають людям безпосередньо змінювати відображуваний URL-адресу. Ви можете собі уявити вразливі місця фішингу, які можуть викликати це.

Єдиний надійний спосіб змінити URL без зміни сторінок - це використання внутрішнього посилання або хеша. наприклад: http://site.com/page.html стає http://site.com/page.html#item1 . Цей прийом часто застосовують у хиджаксах (AJAX + історія збереження).

Роблячи це, я часто використовую посилання для дій з хешем як href, а потім додаю події клацання з jquery, які використовують запитуваний хеш для визначення та делегування дії.

Я сподіваюсь, що це поставить вас на правильний шлях.


Вибачте, але ваша відповідь не відповідає дійсності. Так, ви можете змінити URL-адресу.
Дерек 朕 會 功夫

1
Так, ви можете скористатися програмою html5 api історії, але це не крос-браузер, хоча ви можете використовувати полі-заповнення, яке буде відновлювати хеш-адреси.
Jethro Larson

8

jQuery має чудовий плагін для зміни URL-адреси браузера, який називається jQuery-pushher .

JavaScript pushStateі jQuery можна використовувати разом, як-от:

history.pushState(null, null, $(this).attr('href'));

Приклад:

$('a').click(function (event) {

  // Prevent default click action
  event.preventDefault();     

  // Detect if pushState is available
  if(history.pushState) {
    history.pushState(null, null, $(this).attr('href'));
  }
  return false;
});


Використовуючи лише JavaScript history.pushState() , який змінює реферала, який використовується у заголовку HTTP для об’єктів XMLHttpRequest, створених після зміни стану.

Приклад:

window.history.pushState("object", "Your New Title", "/new-url");

Метод pushState ():

pushState()приймає три параметри: об'єкт стану, заголовок (який на даний момент ігнорується) та (необов'язково) URL. Розглянемо кожен із цих трьох параметрів детальніше:

  1. об’єкт стану - Об'єкт стану - це об’єкт JavaScript, який пов'язаний з новим записом історії, створеним pushState(). Щоразу, коли користувач переходить до нового стану, подія popstate запускається, а державна властивість події містить копію об'єкта стану історії вступу.

    Об'єктом держави може бути все, що можна серіалізувати. Оскільки Firefox зберігає об’єкти стану на диску користувача, щоб їх можна було відновити після того, як користувач перезапустив її браузер, ми накладаємо обмеження розміру 640k символів на серіалізоване представлення об'єкта стану. Якщо ви передасте об'єкт стану, серіалізоване представлення якого більше, ніж це pushState(), метод видасть виняток. Якщо вам потрібно більше місця, ніж це, вам рекомендується використовувати sessionStorage та / або localStorage.

  2. title - Firefox наразі ігнорує цей параметр, хоча він може використовувати його в майбутньому. Передача порожнього рядка тут має бути захищеною від майбутніх змін методу. Крім того, ви можете передати короткий заголовок для стану, в який ви переїжджаєте.

  3. URL - URL-адреса нового запису історії задається цим параметром. Зауважте, що браузер не буде намагатися завантажити цю URL-адресу після виклику pushState(), але може спробувати завантажити URL пізніше, наприклад, після того, як користувач перезапустить свій браузер. Нова URL-адреса не повинна бути абсолютною; якщо вона відносна, вона вирішена відносно поточної URL-адреси. Нова URL-адреса повинна мати те саме походження, що і поточна URL-адреса; інакше pushState()викине виняток. Цей параметр необов’язковий; якщо він не вказаний, він встановлюється в поточну URL-адресу документа.



3

Фотогалерея Facebook робить це за допомогою #hash у URL-адресі. Ось кілька прикладних URL-адрес:

Перш ніж натиснути "наступний":

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507

Після натискання "наступний":

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507#!/photo.php?fbid=496435457507&set=a.218088072507.133423.681812507&pid=5887085&id=681812507

Зауважте, що хеш-баг (#!) Негайно супроводжується новою URL-адресою.



2

Що для мене працює - це history.replaceState()функція, яка полягає в наступному -

history.replaceState(data,"Title of page"[,'url-of-the-page']);

Ця сторінка не буде перезавантажена, ви можете скористатися нею у випадку JavaScript


1

Мені було цікаво, чи це буде можливим, поки батьківський шлях на сторінці однаковий, до нього додається лише щось нове.

Так, скажімо, користувач перебуває на сторінці: http://domain.com/site/page.html тоді браузер може дозволити мені це зробити, location.append = new.html і сторінка стає: http://domain.com/site/page.htmlnew.htmlа браузер не змінює його.

Або просто дозвольте людині змінити параметр get, тож давайте location.get = me=1&page=1.

Так оригінальна сторінка стає, http://domain.com/site/page.html?me=1&page=1і вона не оновлюється.

Проблема # полягає в тому, що дані не кешуються (принаймні, я так не думаю), коли хеш змінюється. Таким чином, це як щоразу під час завантаження нової сторінки, тоді як кнопки назад та вперед на сторінці, що не є Ajax , можуть кешувати дані та не витрачати час на повторне завантаження даних.

З того, що я побачив, історія Yahoo вже завантажує всі дані одразу. Схоже, це не робить жодних запитів Ajax. Отже, коли a divвикористовується для обробки різних методів понаднормових даних, ці дані не зберігаються для кожного стану історії.


1

мій код:

//change address bar
function setLocation(curLoc){
    try {
        history.pushState(null, null, curLoc);
        return false;
    } catch(e) {}
        location.hash = '#' + curLoc;
}

та дії:

setLocation('http://example.com/your-url-here');

і приклад

$(document).ready(function(){
    $('nav li a').on('click', function(){
        if($(this).hasClass('active')) {

        } else {
            setLocation($(this).attr('href'));
        }
            return false;
    });
});

Це все :)


1

Більш просту відповідь, яку я представляю,

window.history.pushState(null, null, "/abc")

це додасться /abcпісля доменного імені в URL-адресі браузера. Просто скопіюйте цей код і вставте його в консоль веб-переглядача та побачте, як URL-адреса змінюється на " https://stackoverflow.com/abc "


0

Я мав успіх у:

location.hash="myValue";

Він просто додає #myValueдо поточної URL-адреси. Якщо вам потрібно запустити подію на сторінці "Завантажити", ви можете використовувати ту саму, location.hashщоб перевірити відповідне значення. Просто не забудьте видалити #значення, повернене location.hashнапр

var articleId = window.location.hash.replace("#","");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.