Modifier une chaîne de requête sans recharger la page

114

Je crée une galerie de photos et je souhaite pouvoir modifier la chaîne de requête et le titre lors de la navigation sur les photos.

Le comportement que je recherche est souvent vu avec certaines implémentations de page continue / infinie, où pendant que vous faites défiler la chaîne de requête continue d'incrémenter le numéro de page ( http://x.com?page=4 ) etc. Cela devrait être simple en théorie, mais j'aimerais quelque chose de sûr sur les principaux navigateurs.

J'ai trouvé ce super article et j'essayais de suivre l'exemple avec window.history.pushstate, mais cela ne semble pas fonctionner pour moi. Et je ne sais pas si c'est idéal car je ne me soucie pas vraiment de modifier l'historique du navigateur.

Je veux juste pouvoir offrir la possibilité de mettre en signet la photo actuellement affichée, sans recharger la page à chaque fois que la photo est modifiée.

Voici un exemple de page infinie qui modifie la chaîne de requête: http://tumbledry.org/

UPDATE a trouvé cette méthode:

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

cela semble fonctionner pour moi, mais je suis sur un nouveau chrome .. cela causerait probablement des problèmes avec les anciens navigateurs?

Sonic Soul
la source
Pouvez-vous publier un lien vers un site d'exemple qui met à jour sa chaîne de requête de manière dynamique? Je ne pense pas que cela puisse être fait, mais vous pouvez modifier la valeur de hachage et cela pourrait suffire à obtenir ce que vous voulez.
Pointy
duplication possible de la façon de manipuler l'URL avec javascript / jquery?
Quentin
duplication possible de Pourquoi le nouveau Web Dropbox peut-il modifier l'URL sans actualisation de la page? et les trois questions, il est marqué comme un duplicata de
Quentin
@Quentin. Vous ne pouvez avoir qu'un seul vote de plus près ...:)
gdoron soutient Monica

Réponses:

185

Si vous recherchez une modification de hachage, votre solution fonctionne correctement. Cependant, si vous souhaitez modifier la requête, vous pouvez utiliser pushState, comme vous l'avez dit. Voici un exemple qui pourrait vous aider à le mettre en œuvre correctement. J'ai testé et cela a bien fonctionné:

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

Il ne recharge pas la page, mais il vous permet uniquement de modifier la requête URL. Vous ne pourrez pas modifier le protocole ou les valeurs d'hôte. Et bien sûr, cela nécessite des navigateurs modernes capables de traiter l'API HTML5 History.

Pour plus d'informations:

http://diveintohtml5.info/history.html

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

Fabio Nolasco
la source
6
Je crois que vous pouvez raccourcir window.location.protocol + '//' + window.location.hostjuste: window.location.origin.
Garrett
4
De plus, pour plus d'informations, les chemins relatifs fonctionnent également avec history.pushState(). Aucun stateargument réel n'est requis non plus. Les deux signifient que vous pouvez faire quelque chose de simple comme history.pushState(null, '', '/foo?bar=true')si votre nouvelle URL est sur le même hôte / port.
Blaskovicz
23
Notez que si vous ne souhaitez pas que le nouvel état apparaisse dans l'historique du navigateur, vous pouvez l'utiliser history.replaceState()avec les mêmes arguments.
Blackus
6
Utilisez history.replaceState () sinon vous devez cliquer deux fois sur le bouton RETOUR dans votre navigateur
Zhenya
4
dans les navigateurs modernes, vous pouvez simplement faire:if (window.history.pushState) { const newURL = new URL(window.location.href); newURL.search = '?myNewUrlQuery=1'; window.history.pushState({ path: newURL.href }, '', newURL.href); }
Allan Baptista
8

Sur la base de la réponse de Fabio, j'ai créé deux fonctions qui seront probablement utiles à quiconque tombe sur cette question. Avec ces deux fonctions, vous pouvez appeler insertParam()avec une clé et une valeur comme argument. Il ajoutera le paramètre URL ou, si un paramètre de requête existe déjà avec la même clé, il changera ce paramètre en la nouvelle valeur:

//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
la source
comment vos fonctions sont meilleures new URLSearchParams()qu'avec ses méthodes natives comme set et delete ? dans les deux cas, nous devons le mettre à l'histoire avechistory.pushState()
AlexNikonov
1
new URLSearchParams()n'est pris en charge par aucune version d'IE
jmona789
Merci @ jmona789 cela a parfaitement fonctionné pour moi et était exactement ce que je recherchais
mknopf
7

J'ai utilisé la bibliothèque JavaScript suivante avec beaucoup de succès:

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

Il prend en charge l'API d'historique HTML5 ainsi qu'une méthode de secours (utilisant #) pour les anciens navigateurs.

Cette bibliothèque est essentiellement un polyfill autour de `history.pushState '.

Ian Newson
la source
impressionnant! l'avez-vous testé avec tous les navigateurs ??
Sonic Soul
Mon implémentation a été testée dans IE7 +, Firefox 3.6+, Safari 5 et Chrome 16+. Cela fonctionne probablement aussi avec d'autres navigateurs, mais je n'ai eu aucune plainte concernant les différents systèmes déployés en l'utilisant.
Ian Newson
génial. donc maintenant .. mettre simplement un # au lieu d'un & lors de l'écriture dans window.location.href fonctionne pour moi. en ce qu'il ne recharge pas la page. je suis sûr qu'il se cassera une fois que je le testerai dans IE .. à quel point j'irai avec la bibliothèque que vous avez suggérée. merci
Sonic Soul
La méthode # est bonne dans la mesure où elle prend en charge un très large navigateur. Les choses peuvent se compliquer lorsque vous devez inclure ces informations dans les requêtes adressées au serveur, car la partie # de l'URL n'est pas envoyée par le navigateur. Il existe des moyens de contourner cela, y compris la bibliothèque que j'ai référencée. En outre, l'utilisation de l'API d'historique HTML5 permet de raccourcir globalement vos URL et nécessite moins de travail côté client pour restaurer l'état.
Ian Newson
La méthode # est également problématique pour le partage des médias sociaux; Twitter, Facebook et peut-être d'autres ne fonctionnent pas bien avec les balises d'ancrage lors de la création d'aperçus ou de liens vers le partage.
mirth23
5

Je souhaite améliorer la réponse de Fabio et créer une fonction qui ajoute une clé personnalisée à la chaîne d'URL sans recharger la page.

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);
    }
}
Aram Hovhannisyan
la source
0

Alors l'API d'historique est exactement ce que vous recherchez. Si vous souhaitez également prendre en charge les navigateurs hérités, recherchez une bibliothèque qui se rabat sur la manipulation de la balise de hachage de l'URL si le navigateur ne fournit pas l'API d'historique.

chucktator
la source