Изменение строки запроса без перезагрузки страницы

114

Я создаю фотогалерею и хочу иметь возможность изменять строку запроса и заголовок при просмотре фотографий.

Поведение, которое я ищу, часто наблюдается в некоторых реализациях непрерывной / бесконечной страницы, где при прокрутке вниз строка запроса продолжает увеличивать номер страницы ( http://x.com?page=4 ) и т. Д. Это должно быть теоретически просто, но я бы хотел что-то безопасное для основных браузеров.

Я нашел этот отличный пост и пытался последовать его примеру window.history.pushstate, но, похоже, мне это не помогло. И я не уверен, что это идеально, потому что меня не особо волнует изменение истории браузера.

Я просто хочу иметь возможность добавлять в закладки просматриваемую в данный момент фотографию, не перезагружая страницу каждый раз при изменении фотографии.

Вот пример бесконечной страницы, изменяющей строку запроса: http://tumbledry.org/

ОБНОВЛЕНИЕ обнаружило этот метод:

window.location.href = window.location.href + '#abc';

похоже, это работает для меня, но я использую новый Chrome .. это, вероятно, вызовет некоторые проблемы со старыми браузерами?

Sonic Soul
источник
Можете ли вы опубликовать ссылку на какой-нибудь пример сайта, который динамически обновляет строку запроса? Я не думаю, что это можно сделать, но вы можете изменить значение хэша, и этого может быть достаточно, чтобы получить то, что вы хотите.
Pointy
возможный дубликат Почему новый веб-Dropbox может изменять URL без обновления страницы? и три вопроса отмечены как дубликаты
Квентин
@ Квентин. У вас может быть только один более близкий голос ...:)
gdoron поддерживает Монику

Ответы:

185

Если вы ищете модификацию хэша, ваше решение работает нормально. Однако, если вы хотите изменить запрос, вы можете использовать pushState, как вы сказали. Вот пример, который может помочь вам правильно его реализовать. Я тестировал, и все работало нормально:

if (history.pushState) {
    var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?myNewUrlQuery=1';
    window.history.pushState({path:newurl},'',newurl);
}

Он не перезагружает страницу, а только позволяет изменить URL-запрос. Вы не сможете изменить протокол или значения хоста. И, конечно же, для этого требуются современные браузеры, которые могут обрабатывать HTML5 History API.

Чтобы получить больше информации:

http://diveintohtml5.info/history.html

https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history

Фабио Ноласко
источник
6
Я считаю , что вы можете сократить window.location.protocol + '//' + window.location.hostпросто: window.location.origin.
Garrett
4
Также, для дополнительной информации, относительные пути также работают с history.pushState(). Никаких реальных stateаргументов тоже не требуется. Оба эти фактора означают, что вы можете сделать что-то простое, например, history.pushState(null, '', '/foo?bar=true')если ваш новый URL-адрес находится на том же хосте / порту.
Blaskovicz
23
Обратите внимание: если вы не хотите, чтобы новое состояние отображалось в истории браузера, вы можете использовать history.replaceState()те же аргументы.
Blackus
6
ИСПОЛЬЗУЙТЕ history.replaceState (), иначе вам нужно дважды нажать кнопку НАЗАД в браузере
Женя,
4
в современных браузерах вы можете просто сделать:if (window.history.pushState) { const newURL = new URL(window.location.href); newURL.search = '?myNewUrlQuery=1'; window.history.pushState({ path: newURL.href }, '', newURL.href); }
Аллан Баптиста
8

Основываясь на ответе Фабио, я создал две функции, которые, вероятно, будут полезны любому, кто наткнется на этот вопрос. С помощью этих двух функций вы можете вызывать insertParam()с ключом и значением в качестве аргумента. Он либо добавит параметр URL, либо, если параметр запроса с таким же ключом уже существует, изменит этот параметр на новое значение:

//function to remove query params from a URL
function removeURLParameter(url, parameter) {
    //better to use l.search if you have a location/link object
    var urlparts= url.split('?');   
    if (urlparts.length>=2) {

        var prefix= encodeURIComponent(parameter)+'=';
        var pars= urlparts[1].split(/[&;]/g);

        //reverse iteration as may be destructive
        for (var i= pars.length; i-- > 0;) {    
            //idiom for string.startsWith
            if (pars[i].lastIndexOf(prefix, 0) !== -1) {  
                pars.splice(i, 1);
            }
        }

        url= urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : "");
        return url;
    } else {
        return url;
    }
}

//function to add/update query params
function insertParam(key, value) {
    if (history.pushState) {
        // var newurl = window.location.protocol + "//" + window.location.host + search.pathname + '?myNewUrlQuery=1';
        var currentUrlWithOutHash = window.location.origin + window.location.pathname + window.location.search;
        var hash = window.location.hash
        //remove any param for the same key
        var currentUrlWithOutHash = removeURLParameter(currentUrlWithOutHash, key);

        //figure out if we need to add the param with a ? or a &
        var queryStart;
        if(currentUrlWithOutHash.indexOf('?') !== -1){
            queryStart = '&';
        } else {
            queryStart = '?';
        }

        var newurl = currentUrlWithOutHash + queryStart + key + '=' + value + hash
        window.history.pushState({path:newurl},'',newurl);
    }
}
jmona789
источник
Чем ваши функции лучше, чем new URLSearchParams()с его собственными методами, такими как установка и удаление ? в любом случае мы должны поместить это в историю сhistory.pushState()
AlexNikonov
1
new URLSearchParams()не поддерживается никакими версиями IE
jmona789 05
Спасибо @ jmona789, это отлично сработало для меня и было именно тем, что я искал
mknopf
7

Я с большим успехом использовал следующую библиотеку JavaScript:

https://github.com/balupton/jquery-history

Он поддерживает API истории HTML5, а также резервный метод (с использованием #) для старых браузеров.

По сути, эта библиотека представляет собой полифил вокруг `history.pushState '.

Ян Ньюсон
источник
здорово! вы тестировали его со всеми браузерами ??
Sonic Soul
Моя реализация была протестирована в IE7 +, Firefox 3.6+, Safari 5 и Chrome 16+. Вероятно, он работает и с другими браузерами, но у меня не было никаких жалоб на несколько систем, развернутых с его использованием.
Ian Newson
здорово. так что прямо сейчас ... у меня работает просто # вместо & при записи в window.location.href. в том, что он не перезагружает страницу. Я уверен, что он сломается, как только я протестирую его в IE ... после этого я воспользуюсь предложенной вами библиотекой. спасибо
Sonic Soul
Метод # хорош тем, что имеет очень широкую поддержку браузерами. Все может усложниться, когда вам нужно включить эту информацию в запросы к серверу, поскольку часть URL-адреса # не отправляется браузером. Есть способы обойти это, включая библиотеку, на которую я ссылался. Кроме того, использование API истории HTML5 помогает сделать ваши URL короче в целом и требует меньше работы на стороне клиента для восстановления состояния.
Ian Newson
Метод # также проблематичен для публикации в социальных сетях; Twitter, Facebook и, возможно, другие не очень хорошо работают с тегами привязки при создании превью или обратных ссылок на общий ресурс.
mirth23
5

Я хочу улучшить ответ Фабио и создать функцию, которая добавляет настраиваемый ключ в строку URL без перезагрузки страницы.

function insertUrlParam(key, value) {
    if (history.pushState) {
        let searchParams = new URLSearchParams(window.location.search);
        searchParams.set(key, value);
        let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams.toString();
        window.history.pushState({path: newurl}, '', newurl);
    }
}
Арам Оганесян
источник
0

Тогда API истории - это именно то, что вам нужно. Если вы хотите поддерживать и устаревшие браузеры, поищите библиотеку, которая использует манипуляции с хэш-тегом URL, если браузер не предоставляет API истории.

чактатор
источник