Modificar una cadena de consulta sin recargar la página

114

Estoy creando una galería de fotos y me gustaría poder cambiar la cadena de consulta y el título cuando se examinan las fotos.

El comportamiento que estoy buscando se ve a menudo con algunas implementaciones de página continua / infinita, donde mientras se desplaza hacia abajo, la cadena de consulta sigue aumentando el número de página ( http://x.com?page=4 ), etc. Esto debería ser simple en teoría, pero me gustaría algo que sea seguro en los principales navegadores.

Encontré esta gran publicación y estaba tratando de seguir el ejemplo de window.history.pushstate, pero eso no parece funcionar para mí. Y no estoy seguro de si es ideal porque realmente no me importa modificar el historial del navegador.

Solo quiero poder ofrecer la posibilidad de marcar la foto que se está viendo actualmente, sin tener que volver a cargar la página cada vez que se cambia la foto.

Aquí hay un ejemplo de página infinita que modifica la cadena de consulta: http://tumbledry.org/

UPDATE encontró este método:

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

parece funcionar para mí, pero estoy en un nuevo Chrome ... ¿probablemente causaría algunos problemas con los navegadores más antiguos?

Sonic Soul
fuente
¿Puede publicar un enlace a algún sitio de ejemplo que actualice su cadena de consulta de forma dinámica? No creo que se puede hacer, pero puedo cambiar el valor hash y que podría ser suficiente para conseguir lo que quiere.
Puntiagudo
posible duplicado de ¿Por qué el nuevo Dropbox web puede cambiar la URL sin actualizar la página? y las tres preguntas de las que está marcado como un duplicado
Quentin
@Quentin. Solo puede tener un voto más cercano ...:)
gdoron está apoyando a Monica

Respuestas:

185

Si está buscando una modificación de Hash, su solución funciona bien. Sin embargo, si desea cambiar la consulta, puede usar pushState, como dijo. Aquí hay un ejemplo que puede ayudarlo a implementarlo correctamente. Probé y funcionó bien:

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

No recarga la página, pero solo le permite cambiar la consulta de URL. No podrá cambiar el protocolo o los valores de host. Y, por supuesto, requiere navegadores modernos que puedan procesar la API de historial de HTML5.

Para más información:

http://diveintohtml5.info/history.html

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

Fabio Nolasco
fuente
6
Creo que se puede acortar window.location.protocol + '//' + window.location.hosta solo: window.location.origin.
Garrett
4
Además, para agregar un poco de información, las rutas relativas también funcionan con history.pushState(). Tampoco statese requiere ningún argumento real . Ambos significan que puede hacer algo simple, como history.pushState(null, '', '/foo?bar=true')si su nueva URL está en el mismo host / puerto.
Blaskovicz
23
Tenga en cuenta que, si no desea que el nuevo estado aparezca en el historial del navegador, puede usarlo history.replaceState()con los mismos argumentos.
Blackus
6
USE history.replaceState () de lo contrario, debe hacer clic en el botón ATRÁS dos veces en su navegador
Zhenya
4
en los navegadores modernos, puede hacer lo siguiente: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

A partir de la respuesta de Fabio, creé dos funciones que probablemente serán útiles para cualquiera que se encuentre con esta pregunta. Con estas dos funciones, puede llamar insertParam()con una clave y un valor como argumento. Agregará el parámetro de URL o, si ya existe un parámetro de consulta con la misma clave, cambiará ese parámetro al nuevo valor:

//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
fuente
¿Cómo sus funciones son mejores que new URLSearchParams()con sus métodos nativos configurados y eliminados ? en cualquier caso debemos ponerlo en la historia conhistory.pushState()
AlexNikonov
1
new URLSearchParams()no es compatible con ninguna versión de IE
jmona789
Gracias @ jmona789 esto funcionó perfectamente para mí y era exactamente lo que estaba buscando
mknopf
7

He utilizado la siguiente biblioteca de JavaScript con gran éxito:

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

Es compatible con la API de historial de HTML5, así como con un método alternativo (usando #) para navegadores más antiguos.

Esta biblioteca es esencialmente un polyfill alrededor de `history.pushState '.

Ian Newson
fuente
¡increíble! ¿Lo probaste con todos los navegadores?
Sonic Soul
Mi implementación fue probada en IE7 +, Firefox 3.6+, Safari 5 y Chrome 16+. Probablemente también funcione con otros navegadores, pero no he tenido ninguna queja en los varios sistemas implementados que lo utilizan.
Ian Newson
Excelente. así que ahora mismo ... simplemente poner un # en lugar de un & al escribir en window.location.href funciona para mí. en que no recarga la página. Estoy seguro de que se romperá una vez que lo pruebe en IE ... momento en el que iré con la biblioteca que sugirió. gracias
Sonic Soul
El método # es bueno porque tiene un soporte de navegador muy amplio. Las cosas pueden complicarse cuando necesita incluir esa información en las solicitudes al servidor, ya que el navegador no envía la parte # de la URL. Hay formas de evitar eso, que incluye la biblioteca a la que hice referencia. Además, el uso de la API de historial HTML5 ayuda a que sus URL sean más cortas en general y requiere menos trabajo del lado del cliente para restaurar el estado.
Ian Newson
El método # también es problemático para compartir en redes sociales; Twitter, Facebook y posiblemente otros no funcionan bien con las etiquetas de anclaje al crear vistas previas o enlaces al recurso compartido.
alegría
5

Quiero mejorar la respuesta de Fabio y crear una función que agregue una clave personalizada a la cadena de URL sin volver a cargar la página.

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
fuente
0

Entonces la API de historial es exactamente lo que está buscando. Si también desea admitir navegadores heredados, busque una biblioteca que se base en la manipulación de la etiqueta hash de la URL si el navegador no proporciona la API de historial.

chucktator
fuente