在一个使用AJAX调用的web应用程序中,我需要提交一个请求,但在URL的末尾添加一个参数,例如:

原始URL:

http://server/myapp.php?id=10

导致的网址:

http://server/myapp.php?id=10&enabled=true

寻找一个JavaScript函数,该函数解析URL并查看每个参数,然后添加新参数或更新已经存在的值。


当前回答

它处理这样的URL:

空 没有任何参数 已经有一些参数 有什么?在最后,但同时没有任何参数

它不处理这样的URL:

带有片段标识符(即散列,#) 如果URL已经有必要的查询参数(那么将会有重复)

适用于:

Chrome 32 + 火狐26 + 野生动物园7.1 +

function appendQueryParameter(url, name, value) {
    if (url.length === 0) {
        return;
    }

    let rawURL = url;

    // URL with `?` at the end and without query parameters
    // leads to incorrect result.
    if (rawURL.charAt(rawURL.length - 1) === "?") {
        rawURL = rawURL.slice(0, rawURL.length - 1);
    }

    const parsedURL = new URL(rawURL);
    let parameters = parsedURL.search;

    parameters += (parameters.length === 0) ? "?" : "&";
    parameters = (parameters + name + "=" + value);

    return (parsedURL.origin + parsedURL.pathname + parameters);
}

使用ES6模板字符串的版本。

适用于:

Chrome 41 + 火狐32 + 野生动物园9.1 +

function appendQueryParameter(url, name, value) {
    if (url.length === 0) {
        return;
    }

    let rawURL = url;

    // URL with `?` at the end and without query parameters
    // leads to incorrect result.
    if (rawURL.charAt(rawURL.length - 1) === "?") {
        rawURL = rawURL.slice(0, rawURL.length - 1);
    }

    const parsedURL = new URL(rawURL);
    let parameters = parsedURL.search;

    parameters += (parameters.length === 0) ? "?" : "&";
    parameters = `${parameters}${name}=${value}`;

    return `${parsedURL.origin}${parsedURL.pathname}${parameters}`;
}

其他回答

这是一个非常简化的版本,为了可读性和更少的代码行而不是微观优化的性能(我们说的是几毫秒的差异,实际上……由于它的性质(操作当前文档的位置),这将很可能在一个页面上运行一次)。

/**
* Add a URL parameter (or changing it if it already exists)
* @param {search} string  this is typically document.location.search
* @param {key}    string  the key to set
* @param {val}    string  value 
*/
var addUrlParam = function(search, key, val){
  var newParam = key + '=' + val,
      params = '?' + newParam;

  // If the "search" string exists, then build params from it
  if (search) {
    // Try to replace an existance instance
    params = search.replace(new RegExp('([?&])' + key + '[^&]*'), '$1' + newParam);

    // If nothing was replaced, then add the new param to the end
    if (params === search) {
      params += '&' + newParam;
    }
  }

  return params;
};

然后你可以这样使用:

document.location.pathname + addUrlParam(document.location.search, 'foo', 'bar');

以下几点:

合并重复的查询字符串参数 使用绝对和相对url 在浏览器和节点中工作

/**
 * Adds query params to existing URLs (inc merging duplicates)
 * @param {string} url - src URL to modify
 * @param {object} params - key/value object of params to add
 * @returns {string} modified URL
 */
function addQueryParamsToUrl(url, params) {

    // if URL is relative, we'll need to add a fake base
    var fakeBase = !url.startsWith('http') ? 'http://fake-base.com' : undefined;
    var modifiedUrl = new URL(url || '', fakeBase);

    // add/update params
    Object.keys(params).forEach(function(key) {
        if (modifiedUrl.searchParams.has(key)) {
            modifiedUrl.searchParams.set(key, params[key]);
        }
        else {
            modifiedUrl.searchParams.append(key, params[key]);
        }
    });

    // return as string (remove fake base if present)
    return modifiedUrl.toString().replace(fakeBase, '');
}

例子:

// returns /guides?tag=api
addQueryParamsToUrl('/guides?tag=hardware', { tag:'api' })

// returns https://orcascan.com/guides?tag=api
addQueryParamsToUrl('https://orcascan.com/guides?tag=hardware', { tag: 'api' })

你需要适应的基本实现是这样的:

function insertParam(key, value) {
    key = encodeURIComponent(key);
    value = encodeURIComponent(value);

    // kvp looks like ['key1=value1', 'key2=value2', ...]
    var kvp = document.location.search.substr(1).split('&');
    let i=0;

    for(; i<kvp.length; i++){
        if (kvp[i].startsWith(key + '=')) {
            let pair = kvp[i].split('=');
            pair[1] = value;
            kvp[i] = pair.join('=');
            break;
        }
    }

    if(i >= kvp.length){
        kvp[kvp.length] = [key,value].join('=');
    }

    // can return this or...
    let params = kvp.join('&');

    // reload page with new params
    document.location.search = params;
}

这大约是正则表达式或基于搜索的解决方案的两倍,但这完全取决于查询字符串的长度和任何匹配的索引


为了完成起见,我以慢速regex方法为基准(大约慢了150%)

function insertParam2(key,value)
{
    key = encodeURIComponent(key); value = encodeURIComponent(value);

    var s = document.location.search;
    var kvp = key+"="+value;

    var r = new RegExp("(&|\\?)"+key+"=[^\&]*");

    s = s.replace(r,"$1"+kvp);

    if(!RegExp.$1) {s += (s.length>0 ? '&' : '?') + kvp;};

    //again, do what you will here
    document.location.search = s;
}

此解决方案使用更新的搜索参数更新窗口的当前URL,而无需实际重新加载页面。这种方法在PWA/SPA上下文中很有用。

function setURLSearchParam(key, value) {
  const url = new URL(window.location.href);
  url.searchParams.set(key, value);
  window.history.pushState({ path: url.href }, '', url.href);
}

这是我自己的尝试,但我将使用annakata的答案,因为它看起来更清晰:

function AddUrlParameter(sourceUrl, parameterName, parameterValue, replaceDuplicates)
{
    if ((sourceUrl == null) || (sourceUrl.length == 0)) sourceUrl = document.location.href;
    var urlParts = sourceUrl.split("?");
    var newQueryString = "";
    if (urlParts.length > 1)
    {
        var parameters = urlParts[1].split("&");
        for (var i=0; (i < parameters.length); i++)
        {
            var parameterParts = parameters[i].split("=");
            if (!(replaceDuplicates && parameterParts[0] == parameterName))
            {
                if (newQueryString == "")
                    newQueryString = "?";
                else
                    newQueryString += "&";
                newQueryString += parameterParts[0] + "=" + parameterParts[1];
            }
        }
    }
    if (newQueryString == "")
        newQueryString = "?";
    else
        newQueryString += "&";
    newQueryString += parameterName + "=" + parameterValue;

    return urlParts[0] + newQueryString;
}

另外,我从stackoverflow上的另一篇文章中找到了这个jQuery插件,如果你需要更多的灵活性,你可以使用它: http://plugins.jquery.com/project/query-object

我认为代码应该是(还没有测试):

return $.query.parse(sourceUrl).set(parameterName, parameterValue).toString();