160

我正在创建一个照片库,并希望能够在浏览照片时更改查询字符串和标题。

我正在寻找的行为经常出现在连续/无限页面的某些实现中,当您向下滚动查询字符串时,会不断增加页码(http://x.com?page=4)等。这应该是理论上很简单,但我想要在主流浏览器中安全的东西。

我找到了这篇很棒的帖子,并试图按照这个例子进行window.history.pushstate操作,但这似乎对我不起作用。而且我不确定它是否理想,因为我并不真正关心修改浏览器历史记录。

我只是希望能够为当前查看的照片添加书签,而无需在每次更改照片时重新加载页面。

这是一个修改查询字符串的无限页面示例:http: //tumbledry.org/

更新找到了这个方法:

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

9 回答 9

247

如果您正在寻找哈希修改,您的解决方案可以正常工作。但是,如果您想更改查询,可以使用 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

于 2013-10-09T18:05:05.540 回答
39

我想改进 Fabio 的答案并创建一个函数,该函数将自定义键添加到 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);
        }
    }

// to remove the specific key
export function removeUrlParameter(paramKey) {
  const url = window.location.href
  console.log("url", url)
  var r = new URL(url)
  r.searchParams.delete(paramKey)
  const newUrl = r.href
  console.log("r.href", newUrl)
  window.history.pushState({ path: newUrl }, '', newUrl)
}
于 2018-12-26T08:55:41.990 回答
8

在 Fabio 的回答的基础上,我创建了两个函数,它们可能对遇到这个问题的人有用。使用这两个函数,您可以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);
    }
}
于 2018-02-20T16:00:53.337 回答
7

我已经成功使用了以下 JavaScript 库:

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

它支持 HTML5 历史 API 以及旧浏览器的后备方法(使用 #)。

这个库本质上是一个围绕“history.pushState”的polyfill。

于 2012-06-10T16:12:59.377 回答
4

由于每个回答这个问题的人似乎都忘记了哈希,我想添加我用来保留所有URL 参数的代码:

const urlParams = new URLSearchParams(window.location.search);

/// Change some part of the URL params

if (history.pushState) {
  const newurl =
    window.location.protocol +
    "//" +
    window.location.host +
    window.location.pathname +
    "?" +
    urlParams.toString() +
    window.location.hash;
  window.history.replaceState({ path: newurl }, "", newurl);
} else {
  window.location.search = urlParams.toString();
}
于 2021-04-12T08:43:25.863 回答
3

如果我们只是想更新查询参数而不触及 URL 的其他部分,则无需重新构建 URL。这就是我使用的:

const addQueryParam = (key, value) => {
  const url = new URL(window.location.href);
  url.searchParams.set(key, value);
  window.history.pushState({}, '', url.toString());
};

const getQueryParam = (key) => {
  const url = new URL(window.location.href);
  return url.searchParams.get(key) || '';
};

于 2021-08-07T10:34:13.443 回答
3

老问题,现代答案,以帮助未来的开发者;使用URL接口:

const url = new URL(window.location);
url.searchParams.set('key', value);
window.history.pushState(null, '', url.toString());

这可以确保您真的只更改所需的查询参数。

于 2022-01-05T10:39:54.357 回答
0

那么历史 API 正是您正在寻找的。如果您也希望支持旧版浏览器,那么在浏览器不提供历史 API 的情况下,寻找一个库来处理 URL 的哈希标记。

于 2012-06-10T15:57:00.840 回答
0

我想我会在 Fabio 和 Aram 的答案中添加一些内容。我想我有时可能想在 url 中保留哈希。但通常不会,所以我将该参数设置为默认为false.

replaceState仍然没有在 Chrome 上设置页面标题。所以我添加了几行来更改标题,如果提供的话。

function insertUrlParam(key, value, title = '', preserve_hash = false) {
    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();
        if(preserve_hash) newurl = newurl + window.location.hash;
        let oldTitle = document.title;
        if(title !== '') {
            window.history.replaceState({path: newurl}, title, newurl);
            if(document.title !== title) { // fallback if above doesn't work
                document.title = title;
            }
        } else { // in case browsers ever clear titles set with empty string
            window.history.replaceState({path: newurl}, oldTitle, newurl);
        }
    }
}
于 2021-08-02T03:29:39.880 回答