我正在创建一个照片库,并且希望能够在浏览照片时更改查询字符串和标题。
我正在寻找的行为经常出现在连续/无限页面的某些实现中,当您向下滚动查询字符串时,会不断增加页码(http://x.com?page=4)等。理论上这应该很简单,但我想要跨主要浏览器安全的东西。
我发现了这篇很棒的文章,并尝试按照
window.history.pushstate
的示例进行操作,但这似乎对我不起作用。而且我不确定它是否理想,因为我并不真正关心修改浏览器历史记录。
我只是希望能够提供为当前查看的照片添加书签的功能,而无需每次更改照片时都重新加载页面。
以下是修改查询字符串的无限页面示例:http://tumbledry.org/
更新找到了这个方法:
window.location.href = window.location.href + '#abc';
如果您正在寻找哈希修改,您的解决方案可以正常工作。但是,如果您想更改查询,可以使用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/Manipulated_the_browser_history
我想改进 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)
}
老问题,现代答案来帮助未来的开发人员;使用 URL 界面:
const url = new URL(window.location);
url.searchParams.set('key', value);
window.history.pushState(null, '', url.toString());
这可确保您确实只更改所需的查询参数。
如果我们只是想更新查询参数而不触及 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) || '';
};
根据 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);
}
}
我使用了以下 JavaScript 库并取得了巨大成功:
https://github.com/balupton/jquery-history
它支持 HTML5 历史 API 以及针对旧版浏览器的后备方法(使用 #)。
这个库本质上是一个围绕“history.pushState”的填充。
由于每个回答这个问题的人似乎都忘记了哈希值,所以我想添加我用来保留 all 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();
}
那么历史 API 正是您所寻找的。如果您也希望支持旧版浏览器,那么请寻找一个在浏览器不提供历史记录 API 的情况下依靠操作 URL 的哈希标签的库。
我想我应该对 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);
}
}
}
我制作了一个自定义挂钩来更新查询参数,而无需重新加载页面。 这是打字稿,你也可以转换成 JavaScript。对路由器 4 友好!
import React, { useState } from 'react';
const useSearchQuery = <T = string>(queryKey: string, defaultValue?: T)=> {
const searchParams = new URLSearchParams(window.location.search);
const [queryValue, setQueryValue] = useState<T>(
(searchParams.get(queryKey) ?? defaultValue) as T,
);
const setSearchParams = (value: T) => {
if (value === queryValue) return;
if (value) {
searchParams.set(queryKey, value as string);
setQueryValue(value);
} else {
searchParams.delete(queryKey);
if (defaultValue) setQueryValue(defaultValue);
}
const newUrl = [window.location.pathname, searchParams.toString()]
.filter(Boolean)
.join('?');
window.history.replaceState(null, '', newUrl);
};
return [queryValue, setSearchParams] as const;
};
export default useSearchQuery;
希望这有帮助!