我编写了以下函数,它实现了我想要达到的目标:
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
}
else {
return uri + separator + key + "=" + value;
}
}
var
,将变量作用域限制在本地函数中。 - Andrea Salicetti更新 (2020):URLSearchParams 现在被所有现代浏览器支持。
与 window.location.search
结合使用,URLSearchParams 实用工具非常有用。例如:
if ('URLSearchParams' in window) {
var searchParams = new URLSearchParams(window.location.search);
searchParams.set("foo", "bar");
window.location.search = searchParams.toString();
}
foo
是否已存在,它都已被设置为bar
。window.location.search
的上述分配将导致页面加载,因此如果不希望出现这种情况,请像下面这样使用历史记录API。if ('URLSearchParams' in window) {
var searchParams = new URLSearchParams(window.location.search)
searchParams.set("foo", "bar");
var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString();
history.pushState(null, '', newRelativePathQuery);
}
现在,您不需要编写自己的正则表达式或逻辑来处理可能存在的查询字符串。
然而,浏览器支持并不好,因为它目前处于实验阶段,仅在最新版本的Chrome、Firefox、Safari、iOS Safari、Android Browser、Android Chrome和Opera中使用。如果您决定使用它,请使用polyfill。
newRelativePathQuery
的末尾即可解决问题:var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString() + window.location.hash;
- kudlohlavecconst url = new URL(window.location); url.searchParams.set("foo", "bar"); window.location = url;
- Joe Boris我已经扩展了这个解决方案,并结合另一个我找到的方案,根据用户的输入替换/更新/删除查询字符串参数并考虑URL的锚点。
不提供值将删除该参数,提供值将添加/更新该参数。如果没有提供URL,则会从window.location中获取URL。
function UpdateQueryString(key, value, url) {
if (!url) url = window.location.href;
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
hash;
if (re.test(url)) {
if (typeof value !== 'undefined' && value !== null) {
return url.replace(re, '$1' + key + "=" + value + '$2$3');
}
else {
hash = url.split('#');
url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
return url;
}
}
else {
if (typeof value !== 'undefined' && value !== null) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
hash = url.split('#');
url = hash[0] + separator + key + '=' + value;
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
return url;
}
else {
return url;
}
}
}
更新
修复了删除查询字符串中第一个参数时出现的错误,重新设计了正则表达式和测试以包括修复。
第二次更新
根据@JarónBarends的建议 - 调整值检查以检查undefined和null以允许设置0值。
第三次更新
修复了直接在井号之前删除查询字符串变量会丢失井号符号的错误。
第四次更新
感谢@rooby指出第一个RegExp对象中的正则表达式优化。由于使用(\? |&)存在问题,因此将初始正则表达式设置为([?&])。
第五次更新
从if / else语句中删除哈希var声明。
value
的真实性(truthiness),当你将它们的值设置为0时,这会导致从查询字符串中删除变量。因此,你应该使用 if (typeof value !== 'undefined' && value !== null) {}
替换 if (value) {}
。请注意保持原文意思不变。 - Jarón Barendshash
被声明了两次 ;) - wlingke您可以使用浏览器的本地URL API以非常简单的方式完成此操作,其中key
和value
分别是您的参数名称和参数值。
const url = new URL(location.href);
url.searchParams.set(key, value);
这将保留URL的所有内容,仅更改或添加一个查询参数。
然后,您可以对url
对象进行任何操作。例如:
// Log the URL string.
console.log(url.href);
// Go to the URL.
location.assign(url);
// Go to the URL, but overwrite this history entry.
location.replace(url);
// Same as `location.assign` without reloading.
history.pushState(null, '', url);
// Same as `location.replace` without reloading.
history.replaceState(null, '', url);
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
var hash = '';
if( uri.indexOf('#') !== -1 ){
hash = uri.replace(/.*#/, '#');
uri = uri.replace(/#.*/, '');
}
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
return uri + separator + key + "=" + value + hash;
}
}
编辑:修复正则表达式中的[?|&]
,应该改为[?&]
,如评论所指出。
编辑:另一种版本支持删除URL参数。我使用value === undefined
表示删除。可以根据需要使用value === false
或甚至是单独的输入参数。
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
if( value === undefined ) {
if (uri.match(re)) {
return uri.replace(re, '$1$2').replace(/[?&]$/, '').replaceAll(/([?&])&+/g, '$1').replace(/[?&]#/, '#');
} else {
return uri;
}
} else {
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
var hash = '';
if( uri.indexOf('#') !== -1 ){
hash = uri.replace(/.*#/, '#');
uri = uri.replace(/#.*/, '');
}
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
return uri + separator + key + "=" + value + hash;
}
}
}
您可以在以下链接中查看其运行效果:https://jsfiddle.net/cdt16wex/
var separator
行移到返回语句的正上方会修复 "/app#/cool?fun=true" 的错误。这将选择“&”作为分隔符,即使尚未有真正的查询字符串参数,仅有客户端参数。 - j_walker_dev[?|&]
应该改为 [?&]
(否则会匹配 |
)。 - bonger"([?|&])"
不太好。请将其修复为 var re = new RegExp("(?|&)" + key + "=.*?(&|#|$)", "i");
或者 var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
(在其他方面也是一个不错的扩展!) - YakovLhttps://www.example.com/?&&&&#baz
。如果我只删除 foo
参数,我会得到这个:https://www.example.com/?&bar=2#baz
,即使只有一个参数,其中仍然有 ? 和 &。 - jkupczak由于现代JavaScript、Node.js和浏览器的支持,我们可以摆脱第三方库旋涡(jquery、query-string等)并使代码更加简洁。
以下是为给定URL添加或更新查询参数的JavaScript(Node.js)和TypeScript版本的函数:
const getUriWithParam = (baseUrl, params) => {
const Url = new URL(baseUrl);
const urlParams = new URLSearchParams(Url.search);
for (const key in params) {
if (params[key] !== undefined) {
urlParams.set(key, params[key]);
}
}
Url.search = urlParams.toString();
return Url.toString();
};
console.info('expected: https://example.com/?foo=bar');
console.log(getUriWithParam("https://example.com", {foo: "bar"}));
console.info('expected: https://example.com/slug?foo=bar#hash');
console.log(getUriWithParam("https://example.com/slug#hash", {foo: "bar"}));
console.info('expected: https://example.com/?bar=baz&foo=bar');
console.log(getUriWithParam("https://example.com?bar=baz", {foo: "bar"}));
console.info('expected: https://example.com/?foo=baz&bar=baz');
console.log(getUriWithParam("https://example.com?foo=bar&bar=baz", {foo: "baz"}));
const getUriWithParam = (
baseUrl: string,
params: Record<string, any>
): string => {
const Url = new URL(baseUrl);
const urlParams: URLSearchParams = new URLSearchParams(Url.search);
for (const key in params) {
if (params[key] !== undefined) {
urlParams.set(key, params[key]);
}
}
Url.search = urlParams.toString();
return Url.toString();
};
URL
在React Native中未实现。因此,您需要事先安装react-native-url-polyfill。
请参见此答案中的第二个解决方案。
这是我的库,用于实现此功能:https://github.com/Mikhus/jsurl
var u = new Url;
u.query.param='value'; // adds or replaces the param
alert(u)
如果它没有被设置,或者想要用新值更新,可以使用:
window.location.search = 'param=value'; // or param=new_value
顺便说一下,这是简单的Javascript。
编辑
你可能想尝试使用jquery query-object 插件。
window.location.search = jQuery.query.set("param", 5);
我知道这个问题已经很老了,而且已经有了很多答案,但是我也想发表一下我的看法。我正在尝试重新发明轮子,因为我曾经使用过目前被接受的答案,但最近在一个项目中,URL片段的处理出了问题。
下面是函数代码。它相当冗长,但是我尽可能地使它具有韧性。如果您有缩短/改进它的建议,我会非常乐意听取。我为它(或其他类似函数)编写了一个小的jsFiddle测试套件。如果一个函数能够通过那里的每一个测试,我认为它应该可以使用。
更新:我发现了一个很酷的函数使用DOM解析URL,所以我在这里加入了这种技术。它使函数变得更短、更可靠。感谢那个函数的作者。
/**
* Add or update a query string parameter. If no URI is given, we use the current
* window.location.href value for the URI.
*
* Based on the DOM URL parser described here:
* http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
*
* @param (string) uri Optional: The URI to add or update a parameter in
* @param (string) key The key to add or update
* @param (string) value The new value to set for key
*
* Tested on Chrome 34, Firefox 29, IE 7 and 11
*/
function update_query_string( uri, key, value ) {
// Use window URL if no query string is provided
if ( ! uri ) { uri = window.location.href; }
// Create a dummy element to parse the URI with
var a = document.createElement( 'a' ),
// match the key, optional square brackets, an equals sign or end of string, the optional value
reg_ex = new RegExp( key + '((?:\\[[^\\]]*\\])?)(=|$)(.*)' ),
// Setup some additional variables
qs,
qs_len,
key_found = false;
// Use the JS API to parse the URI
a.href = uri;
// If the URI doesn't have a query string, add it and return
if ( ! a.search ) {
a.search = '?' + key + '=' + value;
return a.href;
}
// Split the query string by ampersands
qs = a.search.replace( /^\?/, '' ).split( /&(?:amp;)?/ );
qs_len = qs.length;
// Loop through each query string part
while ( qs_len > 0 ) {
qs_len--;
// Remove empty elements to prevent double ampersands
if ( ! qs[qs_len] ) { qs.splice(qs_len, 1); continue; }
// Check if the current part matches our key
if ( reg_ex.test( qs[qs_len] ) ) {
// Replace the current value
qs[qs_len] = qs[qs_len].replace( reg_ex, key + '$1' ) + '=' + value;
key_found = true;
}
}
// If we haven't replaced any occurrences above, add the new parameter and value
if ( ! key_found ) { qs.push( key + '=' + value ); }
// Set the new query string
a.search = '?' + qs.join( '&' );
return a.href;
}
window.location.search是可读/可写的。
然而,修改查询字符串将重定向您所在的页面并从服务器刷新。
如果您尝试的是维护客户端状态(并可能使其可以被书签保存),则应修改URL哈希而不是查询字符串,这样可以保持在同一页上(window.location.hash是可读/可写)。这就是像twitter.com这样的网站使用的方法。
您还需要使后退按钮正常工作,必须将JavaScript事件绑定到哈希更改事件上,一个很好的插件是http://benalman.com/projects/jquery-hashchange-plugin/
String#split
需要第二个参数来设置最大的分割次数。jQuery的map
也会很有帮助。 - jpsimons