是否有一种通过jQuery(或不使用)检索查询字符串值的无插件方法?
如果是,怎么办?如果没有,是否有插件可以这样做?
是否有一种通过jQuery(或不使用)检索查询字符串值的无插件方法?
如果是,怎么办?如果没有,是否有插件可以这样做?
当前回答
可靠地做这件事比一开始想象的要复杂得多。
其他答案中使用的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;
}
}
其他回答
这是我在GitHub上的查询字符串解析代码版本。
它的前缀是jquery.*,但解析函数本身不使用jquery。它非常快,但仍然可以进行一些简单的性能优化。
它还支持URL中的列表和哈希表编码,例如:
arr[]=10&arr[]=20&arr[]=100
or
hash[key1]=hello&hash[key2]=moto&a=How%20are%20you
jQuery.toQueryParams = function(str, separator) {
separator = separator || '&'
var obj = {}
if (str.length == 0)
return obj
var c = str.substr(0,1)
var s = c=='?' || c=='#' ? str.substr(1) : str;
var a = s.split(separator)
for (var i=0; i<a.length; i++) {
var p = a[i].indexOf('=')
if (p < 0) {
obj[a[i]] = ''
continue
}
var k = decodeURIComponent(a[i].substr(0,p)),
v = decodeURIComponent(a[i].substr(p+1))
var bps = k.indexOf('[')
if (bps < 0) {
obj[k] = v
continue;
}
var bpe = k.substr(bps+1).indexOf(']')
if (bpe < 0) {
obj[k] = v
continue;
}
var bpv = k.substr(bps+1, bps+bpe-1)
var k = k.substr(0,bps)
if (bpv.length <= 0) {
if (typeof(obj[k]) != 'object') obj[k] = []
obj[k].push(v)
} else {
if (typeof(obj[k]) != 'object') obj[k] = {}
obj[k][bpv] = v
}
}
return obj;
}
这里发布的一些解决方案效率低下。每次脚本需要访问参数时重复正则表达式搜索是完全不必要的,一个函数将参数拆分为关联数组样式对象就足够了。如果您不使用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对的合法分隔符。它需要更复杂的正则表达式来处理;或&,我认为这是不必要的,因为这很少见;我想说,更不可能两者都使用。如果您需要支持;而不是&,只是在正则表达式中交换它们。
<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]);
}
}
})();
ES2015(ES6)
getQueryStringParams = query => {
return query
? (/^[?#]/.test(query) ? query.slice(1) : query)
.split('&')
.reduce((params, param) => {
let [key, value] = param.split('=');
params[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
return params;
}, {}
)
: {}
};
没有jQuery
var qs = (function(a) {
if (a == "") return {};
var b = {};
for (var i = 0; i < a.length; ++i)
{
var p=a[i].split('=', 2);
if (p.length == 1)
b[p[0]] = "";
else
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split('&'));
URL如下?topic=123&name=query+string,将返回以下内容:
qs["topic"]; // 123
qs["name"]; // query string
qs["nothere"]; // undefined (object)
Google方法
撕扯谷歌的代码,我找到了他们使用的方法:getUrlParameters
function (b) {
var c = typeof b === "undefined";
if (a !== h && c) return a;
for (var d = {}, b = b || k[B][vb], e = b[p]("?"), f = b[p]("#"), b = (f === -1 ? b[Ya](e + 1) : [b[Ya](e + 1, f - e - 1), "&", b[Ya](f + 1)][K](""))[z]("&"), e = i.dd ? ia : unescape, f = 0, g = b[w]; f < g; ++f) {
var l = b[f][p]("=");
if (l !== -1) {
var q = b[f][I](0, l),
l = b[f][I](l + 1),
l = l[Ca](/\+/g, " ");
try {
d[q] = e(l)
} catch (A) {}
}
}
c && (a = d);
return d
}
这是模糊的,但可以理解。它无法工作,因为某些变量未定义。
他们开始在url上查找参数?并且还从散列#中。然后,对于每个参数,它们以等号b[f][p](“=”)分割(看起来像indexOf,它们使用字符的位置来获取键/值)。拆分后,他们检查参数是否有值,如果有值,则存储d的值,否则继续。
最后返回对象d,处理转义和+符号。这个对象和我的一样,它有相同的行为。
我的方法作为jQuery插件
(function($) {
$.QueryString = (function(paramsArray) {
let params = {};
for (let i = 0; i < paramsArray.length; ++i)
{
let param = paramsArray[i]
.split('=', 2);
if (param.length !== 2)
continue;
params[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
}
return params;
})(window.location.search.substr(1).split('&'))
})(jQuery);
用法
//Get a param
$.QueryString.param
//-or-
$.QueryString["param"]
//This outputs something like...
//"val"
//Get all params as object
$.QueryString
//This outputs something like...
//Object { param: "val", param2: "val" }
//Set a param (only in the $.QueryString object, doesn't affect the browser's querystring)
$.QueryString.param = "newvalue"
//This doesn't output anything, it just updates the $.QueryString object
//Convert object into string suitable for url a querystring (Requires jQuery)
$.param($.QueryString)
//This outputs something like...
//"param=newvalue¶m2=val"
//Update the url/querystring in the browser's location bar with the $.QueryString object
history.replaceState({}, '', "?" + $.param($.QueryString));
//-or-
history.pushState({}, '', "?" + $.param($.QueryString));
性能测试(针对正则表达式方法的拆分方法)(jsPerf)
准备代码:方法声明
拆分测试代码
var qs = window.GetQueryString(query);
var search = qs["q"];
var value = qs["value"];
var undef = qs["undefinedstring"];
Regex测试代码
var search = window.getParameterByName("q");
var value = window.getParameterByName("value");
var undef = window.getParameterByName("undefinedstring");
在Windows Server 2008 R2/7 x64上的Firefox 4.0 x86中测试
拆分方法:最快144780±2.17%Regex方法:13891±0.85%|90%慢
使用纯JavaScript和正则表达式的简单解决方案:
alert(getQueryString("p2"));
function getQueryString (Param) {
return decodeURI("http://www.example.com/?p1=p11&p2=p2222".replace(new RegExp("^(?:.*[&?]" + encodeURI(Param).replace(/[.+*]/g, "$&") + "(?:=([^&]*))?)?.*$", "i"), "$1"));
}
Js投标
这些都是很好的答案,但我需要一些更强大的东西,我想你们可能都想拥有我创造的东西。
这是一种简单的库方法,可以对URL参数进行剖析和操作。静态方法有以下子方法,可以在主题URL上调用:
获取主机获取路径获取哈希setHash获取参数获取查询setParam(设置参数)获取参数hasParamremoveParam(删除参数)
例子:
URLParser(url).getParam('myparam1')
var url = "http://www.example.com/folder/mypage.html?myparam1=1&myparam2=2#something";
function URLParser(u){
var path="",query="",hash="",params;
if(u.indexOf("#") > 0){
hash = u.substr(u.indexOf("#") + 1);
u = u.substr(0 , u.indexOf("#"));
}
if(u.indexOf("?") > 0){
path = u.substr(0 , u.indexOf("?"));
query = u.substr(u.indexOf("?") + 1);
params= query.split('&');
}else
path = u;
return {
getHost: function(){
var hostexp = /\/\/([\w.-]*)/;
var match = hostexp.exec(path);
if (match != null && match.length > 1)
return match[1];
return "";
},
getPath: function(){
var pathexp = /\/\/[\w.-]*(?:\/([^?]*))/;
var match = pathexp.exec(path);
if (match != null && match.length > 1)
return match[1];
return "";
},
getHash: function(){
return hash;
},
getParams: function(){
return params
},
getQuery: function(){
return query;
},
setHash: function(value){
if(query.length > 0)
query = "?" + query;
if(value.length > 0)
query = query + "#" + value;
return path + query;
},
setParam: function(name, value){
if(!params){
params= new Array();
}
params.push(name + '=' + value);
for (var i = 0; i < params.length; i++) {
if(query.length > 0)
query += "&";
query += params[i];
}
if(query.length > 0)
query = "?" + query;
if(hash.length > 0)
query = query + "#" + hash;
return path + query;
},
getParam: function(name){
if(params){
for (var i = 0; i < params.length; i++) {
var pair = params[i].split('=');
if (decodeURIComponent(pair[0]) == name)
return decodeURIComponent(pair[1]);
}
}
console.log('Query variable %s not found', name);
},
hasParam: function(name){
if(params){
for (var i = 0; i < params.length; i++) {
var pair = params[i].split('=');
if (decodeURIComponent(pair[0]) == name)
return true;
}
}
console.log('Query variable %s not found', name);
},
removeParam: function(name){
query = "";
if(params){
var newparams = new Array();
for (var i = 0;i < params.length;i++) {
var pair = params[i].split('=');
if (decodeURIComponent(pair[0]) != name)
newparams .push(params[i]);
}
params = newparams;
for (var i = 0; i < params.length; i++) {
if(query.length > 0)
query += "&";
query += params[i];
}
}
if(query.length > 0)
query = "?" + query;
if(hash.length > 0)
query = query + "#" + hash;
return path + query;
},
}
}
document.write("Host: " + URLParser(url).getHost() + '<br>');
document.write("Path: " + URLParser(url).getPath() + '<br>');
document.write("Query: " + URLParser(url).getQuery() + '<br>');
document.write("Hash: " + URLParser(url).getHash() + '<br>');
document.write("Params Array: " + URLParser(url).getParams() + '<br>');
document.write("Param: " + URLParser(url).getParam('myparam1') + '<br>');
document.write("Has Param: " + URLParser(url).hasParam('myparam1') + '<br>');
document.write(url + '<br>');
// Remove the first parameter
url = URLParser(url).removeParam('myparam1');
document.write(url + ' - Remove the first parameter<br>');
// Add a third parameter
url = URLParser(url).setParam('myparam3',3);
document.write(url + ' - Add a third parameter<br>');
// Remove the second parameter
url = URLParser(url).removeParam('myparam2');
document.write(url + ' - Remove the second parameter<br>');
// Add a hash
url = URLParser(url).setHash('newhash');
document.write(url + ' - Set Hash<br>');
// Remove the last parameter
url = URLParser(url).removeParam('myparam3');
document.write(url + ' - Remove the last parameter<br>');
// Remove a parameter that doesn't exist
url = URLParser(url).removeParam('myparam3');
document.write(url + ' - Remove a parameter that doesn\"t exist<br>');