如何用Javascript构建查询字符串

只是想知道Javascript中是否有内置的东西可以接受表单并返回查询参数,例如:"var1=value&var2=value2&arr[]=foo&arr[]=bar..."

我已经想了很多年了。

281700 次浏览

我自己也不完全确定,我记得jQuery在一定程度上做到了这一点,但它根本不能处理分层记录,更不用说以php友好的方式了。

有一件事我很确定,当构建url并将产品粘贴到dom中时,不要仅仅使用字符串胶水来做,否则您将打开自己的方便之门。

例如,某些广告软件内联的版本字符串来自任何运行你的flash。当它是adobe通用的简单字符串时,这是很好的,但是,这是非常幼稚的,并且对于安装了Gnash的人来说,这是一个令人尴尬的混乱,因为Gnash 'es版本字符串恰好包含一个完整的GPL版权许可证,包括url和<标签。在你的字符串胶水广告生成器中使用这个,会导致页面打开,在dom中出现不平衡的HTML。

这个故事的寓意是:

   var foo = document.createElement("elementnamehere");
foo.attribute = allUserSpecifiedDataConsideredDangerousHere;
somenode.appendChild(foo);

不是:

   document.write("<elementnamehere attribute=\""
+ ilovebrokenwebsites
+ "\">"
+ stringdata
+ "</elementnamehere>");

谷歌需要学习这个技巧。我试图报告这个问题,但他们似乎并不在意。子> < /

不,我不认为标准JavaScript内置了这个功能,但Prototype JS有这个功能(当然大多数其他JS框架也有,但我不知道它们),他们称之为序列化

我可以推荐Prototype JS,它工作得很好。我真正注意到的唯一缺点是它的大小(几百kb)和范围(ajax, dom等的大量代码)。因此,如果你只想要一个表单序列化器,严格来说,如果你只想要它的Ajax功能(这是我使用它的主要目的),它是多余的。除非你很小心,否则你可能会发现它做了太多的“魔法”(比如用Prototype JS函数扩展它接触的每个dom元素,只是为了找到元素),使得它在极端情况下变慢。

正如Stein所说,你可以使用http://www.prototypejs.org中的原型javascript库。 包括JS,这很简单,$('formName').serialize()将返回你想要的!< / p >

如果您不想使用库,这应该涵盖大多数/所有相同的表单元素类型。

function serialize(form) {
if (!form || !form.elements) return;


var serial = [], i, j, first;
var add = function (name, value) {
serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
}


var elems = form.elements;
for (i = 0; i < elems.length; i += 1, first = false) {
if (elems[i].name.length > 0) { /* don't include unnamed elements */
switch (elems[i].type) {
case 'select-one': first = true;
case 'select-multiple':
for (j = 0; j < elems[i].options.length; j += 1)
if (elems[i].options[j].selected) {
add(elems[i].name, elems[i].options[j].value);
if (first) break; /* stop searching for select-one */
}
break;
case 'checkbox':
case 'radio': if (!elems[i].checked) break; /* else continue */
default: add(elems[i].name, elems[i].value); break;
}
}
}


return serial.join('&');
}

对于我们这些喜欢jQuery的人来说,你可以使用表单插件:http://plugins.jquery.com/project/form,它包含一个formSerialize方法。

你实际上不需要一个表单来做这个Prototype。只需使用对象。toQueryString函数:

Object.toQueryString({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })


// -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'

这并没有直接回答您的问题,但这里有一个通用函数,它将创建一个包含查询字符串参数的URL。参数(名称和值)被安全转义以包含在URL中。

function buildUrl(url, parameters){
var qs = "";
for(var key in parameters) {
var value = parameters[key];
qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
}
if (qs.length > 0){
qs = qs.substring(0, qs.length-1); //chop off last "&"
url = url + "?" + qs;
}
return url;
}


// example:
var url = "http://example.com/";


var parameters = {
name: "George Washington",
dob: "17320222"
};


console.log(buildUrl(url, parameters));
// => http://www.example.com/?name=George%20Washington&dob=17320222

如果你正在使用jQuery,你可能想要检查jQuery.param() http://api.jquery.com/jQuery.param/

例子:

var params = {
parameter1: 'value1',
parameter2: 'value2',
parameter3: 'value3'
};
var query = $.param(params);
console.log(query);

这将打印出:

parameter1=value1&parameter2=value2&parameter3=value3

在jQuery中,你可以通过$.param来做到这一点

$.param({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })


// -> "action=ship&order_id=123&fees%5B%5D=f1&fees%5B%5D=f2&label=a+demo"
现在回答你的问题可能太迟了。
我有同样的问题,我不喜欢不断追加字符串创建URL。所以,我开始使用$。param as techhouse解释。
我还找到了一个URI.js库,它可以轻松地为你创建url。有几个例子可以帮助你:URI.js文档.
下面是其中一个:

var uri = new URI("?hello=world");
uri.setSearch("hello", "mars"); // returns the URI instance for chaining
// uri == "?hello=mars"


uri.setSearch({ foo: "bar", goodbye : ["world", "mars"] });
// uri == "?hello=mars&foo=bar&goodbye=world&goodbye=mars"


uri.setSearch("goodbye", "sun");
// uri == "?hello=mars&foo=bar&goodbye=sun"


// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.setSearch("foo", ["bar", "baz"]);
uri.setSearch("foo[]", ["bar", "baz"]);`

2k20更新:使用杰克的解决方案与URLSearchParams.toString ()

旧的回答:


没有jQuery

var params = {
parameter1: 'value_1',
parameter2: 'value 2',
parameter3: 'value&3'
};


var esc = encodeURIComponent;
var query = Object.keys(params)
.map(k => esc(k) + '=' + esc(params[k]))
.join('&');

对于不支持需要ES5的箭头函数语法的浏览器,将.map...行更改为

    .map(function(k) {return esc(k) + '=' + esc(params[k]);})

变量的名称可以帮助。

所以,你可以

const querystring = require('querystring')


url += '?' + querystring.stringify(parameters)

URLSearchParams API在所有现代浏览器中都可用。例如:

const params = new URLSearchParams({
var1: "value",
var2: "value2",
arr: "foo",
});
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"

ES2017 (ES8)

使用Object.entries(),它返回对象的[key, value]对数组。例如,对于{a: 1, b: 2},它将返回[['a', 1], ['b', 2]]。只有IE不支持(将来也不会)。

代码:

const buildURLQuery = obj =>
Object.entries(obj)
.map(pair => pair.map(encodeURIComponent).join('='))
.join('&');

例子:

buildURLQuery({name: 'John', gender: 'male'});

结果:

"name=John&gender=male"

现在,你可以用FormDataURLSearchParams来实现这一点,而不需要循环任何东西。

const formData = new FormData(form);
const searchParams = new URLSearchParams(formData);
const queryString = searchParams.toString();

不过,旧的浏览器将需要一个填充。

这些答案是非常有用的,但我想添加另一个答案,这可能会帮助你建立完整的URL。 这可以帮助你连接基地urlpathhashparameters
var url = buildUrl('http://mywebsite.com', {
path: 'about',
hash: 'contact',
queryParams: {
'var1': 'value',
'var2': 'value2',
'arr[]' : 'foo'
}
});
console.log(url);

你可以通过npm https://www.npmjs.com/package/build-url下载

演示:

;(function () {
'use strict';


var root = this;
var previousBuildUrl = root.buildUrl;


var buildUrl = function (url, options) {
var queryString = [];
var key;
var builtUrl;
var caseChange;
    

// 'lowerCase' parameter default = false,
if (options && options.lowerCase) {
caseChange = !!options.lowerCase;
} else {
caseChange = false;
}


if (url === null) {
builtUrl = '';
} else if (typeof(url) === 'object') {
builtUrl = '';
options = url;
} else {
builtUrl = url;
}


if(builtUrl && builtUrl[builtUrl.length - 1] === '/') {
builtUrl = builtUrl.slice(0, -1);
}


if (options) {
if (options.path) {
var localVar = String(options.path).trim();
if (caseChange) {
localVar = localVar.toLowerCase();
}
if (localVar.indexOf('/') === 0) {
builtUrl += localVar;
} else {
builtUrl += '/' + localVar;
}
}


if (options.queryParams) {
for (key in options.queryParams) {
if (options.queryParams.hasOwnProperty(key) && options.queryParams[key] !== void 0) {
var encodedParam;
if (options.disableCSV && Array.isArray(options.queryParams[key]) && options.queryParams[key].length) {
for(var i = 0; i < options.queryParams[key].length; i++) {
encodedParam = encodeURIComponent(String(options.queryParams[key][i]).trim());
queryString.push(key + '=' + encodedParam);
}
} else {
if (caseChange) {
encodedParam = encodeURIComponent(String(options.queryParams[key]).trim().toLowerCase());
}
else {
encodedParam = encodeURIComponent(String(options.queryParams[key]).trim());
}
queryString.push(key + '=' + encodedParam);
}
}
}
builtUrl += '?' + queryString.join('&');
}


if (options.hash) {
if(caseChange)
builtUrl += '#' + String(options.hash).trim().toLowerCase();
else
builtUrl += '#' + String(options.hash).trim();
}
}
return builtUrl;
};


buildUrl.noConflict = function () {
root.buildUrl = previousBuildUrl;
return buildUrl;
};


if (typeof(exports) !== 'undefined') {
if (typeof(module) !== 'undefined' && module.exports) {
exports = module.exports = buildUrl;
}
exports.buildUrl = buildUrl;
} else {
root.buildUrl = buildUrl;
}
}).call(this);




var url = buildUrl('http://mywebsite.com', {
path: 'about',
hash: 'contact',
queryParams: {
'var1': 'value',
'var2': 'value2',
'arr[]' : 'foo'
}
});
console.log(url);

var params = { width:1680, height:1050 };
var str = jQuery.param( params );


console.log(str)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

我知道这个回答有点晚了,但效果很好……

var obj = {
a:"a",
b:"b"
}


Object.entries(obj).map(([key, val])=>`${key}=${val}`).join("&");

注意:对象。条目将返回键、值对

上面一行的输出将是一个=第一部;b = b

希望它能帮助到一些人。

快乐的编码…

可能有点多余,但我找到的最干净的方法是建立在这里的一些答案上:

const params: {
key1: 'value1',
key2: 'value2',
key3: 'value3',
}


const esc = encodeURIComponent;
const query = Object.keys(params)
.map(k => esc(k) + '=' + esc(params[k]))
.join('&');


return fetch('my-url', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: query,
})

Source .

创建一个URL对象,并将值附加到seachParameters

let stringUrl = "http://www.google.com/search";
let url = new URL(stringUrl);
let params = url.searchParams;
params.append("q", "This is seach query");


console.log(url.toString());

输出将是

http://www.google.com/search?q=This+is+seach+query

UrlSearchParams API是一个很好的建议,但我不敢相信没有人提到非常有用的.get.set方法。它们可以用于操作查询字符串,不仅非常容易使用,还可以解决您可能遇到的许多问题。例如,在我的例子中,我想构建一个没有重复键的查询字符串。.set为你解决了这个问题。引用自MDN文档:

< >强URLSearchParams.set () 将与给定搜索参数关联的值设置为给定值。

.如果有多个值,则删除其余值

例子(从MDN):

let url = new URL('https://example.com?foo=1&bar=2');
let params = new URLSearchParams(url.search);


// Add a third parameter
params.set('baz', 3);


params.toString(); // "foo=1&bar=2&baz=3"

另一种更短的语法:

let url = new URL('https://example.com?foo=1&bar=2');


// Add a third parameter
url.searchParams.set('baz', 3);


url.searchParams.toString(); // "foo=1&bar=2&baz=3"

删除未定义的参数💪😃

    urlParams = obj =>{
const removeUndefined = JSON.parse(JSON.stringify(obj))
const result = new URLSearchParams(removeUndefined).toString();
return result ? `?${result}`: '';
}
console.log(urlParams({qwe: undefined, txt: 'asd'})) // '?txt=asd'
console.log(urlParams({qwe: undefined})) // ''