是否有一种通过jQuery(或不使用)检索查询字符串值的无插件方法?

如果是,怎么办?如果没有,是否有插件可以这样做?


当前回答

非常轻量级的jQuery方法:

var qs = window.location.search.replace('?','').split('&'),
    request = {};
$.each(qs, function(i,v) {
    var initial, pair = v.split('=');
    if(initial = request[pair[0]]){
        if(!$.isArray(initial)) {
            request[pair[0]] = [initial]
        }
        request[pair[0]].push(pair[1]);
    } else {
        request[pair[0]] = pair[1];
    }
    return;
});
console.log(request);

例如,提醒?q

alert(request.q)

其他回答

这里发布的一些解决方案效率低下。每次脚本需要访问参数时重复正则表达式搜索是完全不必要的,一个函数将参数拆分为关联数组样式对象就足够了。如果您不使用HTML5历史API,则每次加载页面只需要一次。这里的其他建议也无法正确解码URL。

var urlParams;
(window.onpopstate = function () {
    var match,
        pl     = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
        query  = window.location.search.substring(1);
  
    urlParams = {};
    while (match = search.exec(query))
       urlParams[decode(match[1])] = decode(match[2]);
})();

示例查询字符串:

?i=main&mode=front&sid=de8d49b78a85a322c4155015fdce22c4&enc=+Hello%20&empty

结果:

 urlParams = {
    enc: " Hello ",
    i: "main",
    mode: "front",
    sid: "de8d49b78a85a322c4155015fdce22c4",
    empty: ""
}

alert(urlParams["mode"]);
// -> "front"

alert("empty" in urlParams);
// -> true

这也可以很容易地改进为处理数组样式的查询字符串。这里有一个这样的例子,但由于RFC 3986中没有定义数组样式参数,所以我不会用源代码污染这个答案。对于那些对“污染”版本感兴趣的人,请看下面坎贝尔的答案。

此外,正如评论中指出的;是key=value对的合法分隔符。它需要更复杂的正则表达式来处理;或&,我认为这是不必要的,因为这很少见;我想说,更不可能两者都使用。如果您需要支持;而不是&,只是在正则表达式中交换它们。


If you're using a server-side preprocessing language, you might want to use its native JSON functions to do the heavy lifting for you. For example, in PHP you can write:
<script>var urlParams = <?php echo json_encode($_GET, JSON_HEX_TAG);?>;</script>

简单多了!

#已更新

一个新的功能是检索重复的参数,如下myparam=1和myparam=2。然而,没有一个规范,目前的大多数方法都遵循数组的生成。

myparam = ["1", "2"]

因此,这是管理它的方法:

let urlParams = {};
(window.onpopstate = function () {
    let match,
        pl = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) {
            return decodeURIComponent(s.replace(pl, " "));
        },
        query = window.location.search.substring(1);

    while (match = search.exec(query)) {
        if (decode(match[1]) in urlParams) {
            if (!Array.isArray(urlParams[decode(match[1])])) {
                urlParams[decode(match[1])] = [urlParams[decode(match[1])]];
            }
            urlParams[decode(match[1])].push(decode(match[2]));
        } else {
            urlParams[decode(match[1])] = decode(match[2]);
        }
    }
})();

Node.js的源代码中有一个健壮的实现https://github.com/joyent/node/blob/master/lib/querystring.js

TJ的qs也执行嵌套参数解析https://github.com/visionmedia/node-querystring

snipplr.com上的Roshambo有一个简单的脚本来实现这一点,这在使用jQuery|Improved获取URL参数中有所描述。使用他的脚本,您还可以轻松地提取所需的参数。

要点如下:

$.urlParam = function(name, url) {
    if (!url) {
     url = window.location.href;
    }
    var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(url);
    if (!results) {
        return undefined;
    }
    return results[1] || undefined;
}

然后从查询字符串中获取参数。

那么,如果URL/查询字符串是xyz.example/index.html?lang=de。

只需调用var langval=$.urlParam('lang');,你已经得到了。

UZBEKJON也在这方面发表了一篇很棒的博客文章,用jQuery获取URL参数和值。

这是Andy E链接的“句柄数组样式查询字符串”版本的扩展版本。修复了一个错误(?key=1&key[]=2&key[]=3;1丢失并替换为[2,3]),进行了一些小的性能改进(重新解码值,重新计算“[”位置等),并添加了一些改进(功能化,支持?key=1&key=2,支持;分隔符)。我将变量留得很短,但添加了大量注释以使其可读(哦,我在本地函数中重用了v,如果这令人困惑,很抱歉;)。

它将处理以下查询字符串。。。

?test=Hello&pers=neek&pers[]=jeff&pers[][]=jim&pers[extra]=john&test3&nocache=13989148914891264

…把它做成一个看起来像。。。

{
    "test": "Hello",
    "person": {
        "0": "neek",
        "1": "jeff",
        "2": "jim",
        "length": 3,
        "extra": "john"
    },
    "test3": "",
    "nocache": "1398914891264"
}

如上所述,此版本处理一些“格式错误”数组,即-person=neek&person[]=jeff&person[]=jim或person=neek/person=jeff/person=jim,因为密钥是可识别的和有效的(至少在dotNet的NameValueCollection.Add中):

如果目标NameValueCollection中已存在指定的键例如,指定的值将添加到现有的逗号分隔的格式为“value1,value2,value3”的值列表。

似乎陪审团对重复的键有点不满意,因为没有规范。在这种情况下,多个键被存储为一个(假)数组。但请注意,我不会将基于逗号的值处理为数组。

代码:

getQueryStringKey = function(key) {
    return getQueryStringAsObject()[key];
};


getQueryStringAsObject = function() {
    var b, cv, e, k, ma, sk, v, r = {},
        d = function (v) { return decodeURIComponent(v).replace(/\+/g, " "); }, //# d(ecode) the v(alue)
        q = window.location.search.substring(1), //# suggested: q = decodeURIComponent(window.location.search.substring(1)),
        s = /([^&;=]+)=?([^&;]*)/g //# original regex that does not allow for ; as a delimiter:   /([^&=]+)=?([^&]*)/g
    ;

    //# ma(make array) out of the v(alue)
    ma = function(v) {
        //# If the passed v(alue) hasn't been setup as an object
        if (typeof v != "object") {
            //# Grab the cv(current value) then setup the v(alue) as an object
            cv = v;
            v = {};
            v.length = 0;

            //# If there was a cv(current value), .push it into the new v(alue)'s array
            //#     NOTE: This may or may not be 100% logical to do... but it's better than loosing the original value
            if (cv) { Array.prototype.push.call(v, cv); }
        }
        return v;
    };

    //# While we still have key-value e(ntries) from the q(uerystring) via the s(earch regex)...
    while (e = s.exec(q)) { //# while((e = s.exec(q)) !== null) {
        //# Collect the open b(racket) location (if any) then set the d(ecoded) v(alue) from the above split key-value e(ntry) 
        b = e[1].indexOf("[");
        v = d(e[2]);

        //# As long as this is NOT a hash[]-style key-value e(ntry)
        if (b < 0) { //# b == "-1"
            //# d(ecode) the simple k(ey)
            k = d(e[1]);

            //# If the k(ey) already exists
            if (r[k]) {
                //# ma(make array) out of the k(ey) then .push the v(alue) into the k(ey)'s array in the r(eturn value)
                r[k] = ma(r[k]);
                Array.prototype.push.call(r[k], v);
            }
            //# Else this is a new k(ey), so just add the k(ey)/v(alue) into the r(eturn value)
            else {
                r[k] = v;
            }
        }
        //# Else we've got ourselves a hash[]-style key-value e(ntry) 
        else {
            //# Collect the d(ecoded) k(ey) and the d(ecoded) sk(sub-key) based on the b(racket) locations
            k = d(e[1].slice(0, b));
            sk = d(e[1].slice(b + 1, e[1].indexOf("]", b)));

            //# ma(make array) out of the k(ey) 
            r[k] = ma(r[k]);

            //# If we have a sk(sub-key), plug the v(alue) into it
            if (sk) { r[k][sk] = v; }
            //# Else .push the v(alue) into the k(ey)'s array
            else { Array.prototype.push.call(r[k], v); }
        }
    }

    //# Return the r(eturn value)
    return r;
};

可靠地做这件事比一开始想象的要复杂得多。

其他答案中使用的location.search很脆弱,应该避免使用-例如,如果有人搞砸了,并在?查询字符串。在我看来,URL在浏览器中自动转义的方式有很多种,这使得decodeURIComponent非常强制性。许多查询字符串是由用户输入生成的,这意味着对URL内容的假设非常糟糕。包括非常基本的东西,比如每个键都是唯一的,甚至有一个值。

为了解决这个问题,这里提供了一个可配置的API,并提供了健康的防御性编程。请注意,如果您愿意对某些变量进行硬编码,或者如果输入不能包含hasOwnProperty等,则可以将其大小减半。

版本1:返回包含每个参数的名称和值的数据对象。它有效地消除了重复,并始终尊重从左到右找到的第一个。

function getQueryData(url, paramKey, pairKey, missingValue, decode) {

    var query, queryStart, fragStart, pairKeyStart, i, len, name, value, result;

    if (!url || typeof url !== 'string') {
        url = location.href; // more robust than location.search, which is flaky
    }
    if (!paramKey || typeof paramKey !== 'string') {
        paramKey = '&';
    }
    if (!pairKey || typeof pairKey !== 'string') {
        pairKey = '=';
    }
    // when you do not explicitly tell the API...
    if (arguments.length < 5) {
        // it will unescape parameter keys and values by default...
        decode = true;
    }

    queryStart = url.indexOf('?');
    if (queryStart >= 0) {
        // grab everything after the very first ? question mark...
        query = url.substring(queryStart + 1);
    } else {
        // assume the input is already parameter data...
        query = url;
    }
    // remove fragment identifiers...
    fragStart = query.indexOf('#');
    if (fragStart >= 0) {
        // remove everything after the first # hash mark...
        query = query.substring(0, fragStart);
    }
    // make sure at this point we have enough material to do something useful...
    if (query.indexOf(paramKey) >= 0 || query.indexOf(pairKey) >= 0) {
        // we no longer need the whole query, so get the parameters...
        query = query.split(paramKey);
        result = {};
        // loop through the parameters...
        for (i = 0, len = query.length; i < len; i = i + 1) {
            pairKeyStart = query[i].indexOf(pairKey);
            if (pairKeyStart >= 0) {
                name = query[i].substring(0, pairKeyStart);
            } else {
                name = query[i];
            }
            // only continue for non-empty names that we have not seen before...
            if (name && !Object.prototype.hasOwnProperty.call(result, name)) {
                if (decode) {
                    // unescape characters with special meaning like ? and #
                    name = decodeURIComponent(name);
                }
                if (pairKeyStart >= 0) {
                    value = query[i].substring(pairKeyStart + 1);
                    if (value) {
                        if (decode) {
                            value = decodeURIComponent(value);
                        }
                    } else {
                        value = missingValue;
                    }
                } else {
                    value = missingValue;
                }
                result[name] = value;
            }
        }
        return result;
    }
}

版本2:返回一个具有两个相同长度数组的数据映射对象,一个用于名称,另一个用于值,每个参数都有一个索引。此格式支持重复名称,并故意不消除重复名称,因为这可能就是您希望使用此格式的原因。

function getQueryData(url, paramKey, pairKey, missingValue, decode) {

    var query, queryStart, fragStart, pairKeyStart, i, len, name, value, result;

    if (!url || typeof url !== 'string') {
          url = location.href; // more robust than location.search, which is flaky
    }
        if (!paramKey || typeof paramKey !== 'string') {
            paramKey = '&';
        }
        if (!pairKey || typeof pairKey !== 'string') {
            pairKey = '=';
        }
        // when you do not explicitly tell the API...
        if (arguments.length < 5) {
            // it will unescape parameter keys and values by default...
            decode = true;
        }

        queryStart = url.indexOf('?');
        if (queryStart >= 0) {
            // grab everything after the very first ? question mark...
            query = url.substring(queryStart + 1);
        } else {
            // assume the input is already parameter data...
            query = url;
        }
        // remove fragment identifiers...
        fragStart = query.indexOf('#');
        if (fragStart >= 0) {
            // remove everything after the first # hash mark...
            query = query.substring(0, fragStart);
        }
        // make sure at this point we have enough material to do something useful...
        if (query.indexOf(paramKey) >= 0 || query.indexOf(pairKey) >= 0) {
            // we no longer need the whole query, so get the parameters...
            query = query.split(paramKey);
            result = {
                names: [],
                values: []
            };
            // loop through the parameters...
            for (i = 0, len = query.length; i < len; i = i + 1) {
                pairKeyStart = query[i].indexOf(pairKey);
                if (pairKeyStart >= 0) {
                    name = query[i].substring(0, pairKeyStart);
                } else {
                    name = query[i];
                }
                // only continue for non-empty names...
                if (name) {
                    if (decode) {
                        // unescape characters with special meaning like ? and #
                        name = decodeURIComponent(name);
                    }
                    if (pairKeyStart >= 0) {
                        value = query[i].substring(pairKeyStart + 1);
                        if (value) {
                            if (decode) {
                                value = decodeURIComponent(value);
                            }
                        } else {
                            value = missingValue;
                        }
                    } else {
                        value = missingValue;
                    }
                    result.names.push(name);
                    result.values.push(value);
                }
           }
           return result;
       }
   }