Cách xây dựng chuỗi truy vấn bằng Javascript


167

Chỉ cần tự hỏi nếu có bất kỳ thứ gì được tích hợp sẵn trong Javascript có thể lấy Biểu mẫu và trả về các tham số truy vấn, ví dụ: "var1=value&var2=value2&arr[]=foo&arr[]=bar..."

Tôi đã tự hỏi điều này trong nhiều năm.



Câu trả lời:


-24

Tôi đã cố gắng tìm kiếm một câu trả lời cho câu hỏi này một thời gian trước đây, nhưng cuối cùng tôi đã viết hàm riêng của mình để trích xuất các giá trị từ biểu mẫu ..

nó không hoàn hảo nhưng nó phù hợp với nhu cầu của tôi

function form_params( form )
{
    var params = new Array()
    var length = form.elements.length
    for( var i = 0; i < length; i++ )
    {
        element = form.elements[i]

        if(element.tagName == 'TEXTAREA' )
        {
            params[element.name] = element.value
        }
        else if( element.tagName == 'INPUT' )
        {
            if( element.type == 'text' || element.type == 'hidden' || element.type == 'password')
            {
                params[element.name] = element.value
            }
            else if( element.type == 'radio' && element.checked )
            {
                if( !element.value )
                    params[element.name] = "on"
                else
                    params[element.name] = element.value

            }
            else if( element.type == 'checkbox' && element.checked )
            {
                if( !element.value )
                    params[element.name] = "on"
                else
                    params[element.name] = element.value
            }
        }
    }
    return params;
}

form_params trả về ánh xạ (khóa -> giá trị) của các tham số. đầu vào là phần tử biểu mẫu (Phần tử DOM)

Nó không xử lý các trường cho phép nhiều lựa chọn.


44
Có phải chỉ tôi hoặc điều này không trả lời câu hỏi nào cả? Ông đang yêu cầu một chuỗi truy vấn, không phải là một mảng được ánh xạ.
Jake Wilson

2
@JakeWilson Vâng, câu trả lời này chỉ trả lời một nửa câu hỏi. Mảng vẫn cần vào một định dạng chuỗi truy vấn.
Hutch Moore

8
wow tôi phải là một người mới ở JS hồi đó. Sử dụng new Array()để khởi tạo một từ điển. Nhưng sau đó, một lần nữa, mã trông sạch sẽ hơn rất nhiều so với một số thứ nhảm nhí tôi sẽ viết những ngày này!
hasen

2
@hasen có lẽ bạn sẽ xem xét chỉnh sửa câu trả lời này, hoặc, ừm, xóa nó đi? Nó ngày càng có nhiều lượt tải xuống mỗi lần tôi di chuyển đến nó = -D (Tôi thậm chí còn nhớ thời gian nó có tỷ lệ dương ...)
Klesun

1
@ArturKlesun phải, không. Tôi không quan tâm. Bạn có thể thử hỏi người hỏi câu hỏi để không chấp nhận câu trả lời này.
hasen

220

Cập nhật 2k20: sử dụng giải pháp của Josh với URLSearchParams.toString () .

Câu trả lời cũ:


Không có 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('&');

Đối với các trình duyệt không hỗ trợ cú pháp hàm mũi tên yêu cầu ES5, hãy thay đổi .map...dòng thành

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

8
Giải pháp tốt nhất tôi từng thấy - rất sạch sẽ và súc tích. Một vài cảnh báo, mặc dù. 1) trong .map (), cả k và params [k] nên được mã hóa, ví dụ encodeURIComponent (k) và encodeURIComponent (params [k]). 2) Bạn được phép có nhiều hơn một thể hiện của một tham số được đặt tên trong chuỗi truy vấn. Nếu bạn muốn khả năng đó, bạn sẽ phải sử dụng một mảng thay vì một đối tượng (hầu hết các ứng dụng sẽ không muốn hoặc không cần điều đó).
John Deighan

9
3) Không phải tất cả các trình duyệt sẽ hỗ trợ cú pháp chức năng mũi tên (yêu cầu ES5). Nếu bạn muốn hỗ trợ tất cả các trình duyệt (và mã hóa các phần), hãy thay thế .map () ở trên bằng .map (function (k) {return encodeURIComponent (k) + '=' + encodeURIComponent (params [k]);})
John Deighan

1
Xinh đẹp. Thật sự rất đẹp.
Mikko Ohtamaa

9
"không đủ jquery"
Eugene Pankov

1
@ user1738579 Tôi đã chỉnh sửa câu trả lời để bao gồm ví dụ của bạn cho không phải ES5.
Taylor Edmiston

134

Nếu bạn đang sử dụng jQuery, bạn có thể muốn xem jQuery.param() http://api.jquery.com/jQuery.param/

Thí dụ:

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

13
Đây thực sự là câu trả lời chính xác! Chuỗi truy vấn cho một hình thức là $.param($('#myform').serializeArray()).
Jesse

7
@Jlie, đó sẽ là kết quả tương tự như:$('#myform').serialize()
cleaver

94
jQuery !== JavaScript
gphilip

14
@gphilip Đó là lý do tại sao tôi bắt đầu phản hồi với "Nếu bạn đang sử dụng jQuery ...". Mặt khác, nếu bạn muốn triển khai nó trong vanilla JS, bạn có thể kiểm tra việc triển khai jQuery.param()tại đây github.com/jquery/jquery/blob/master/src/serialize.js :)
Klemen Tušar

2
Không giống như câu trả lời của tôi, cái này hỗ trợ các đối tượng lồng nhau nhưsomeStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2
Klesun

113

API URLSearchParams có sẵn trong tất cả các trình duyệt hiện đại. Ví dụ:

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


3
Câu trả lời hay nhất ở đây imo. Chỉ cần thêm vào nó, bạn có thể thực hiện params.append(key, value)sau để thêm thông số tìm kiếm mới trong các tình huống phức tạp hơn.
Mingwei Zhang

4
Lưu ý rằng các giá trị không xác định và null được bao gồm trong chuỗi cuối cùng:x=null&y=undefined
pomber

2
Ngoài ra, nếu bạn đã có một đối tượng URL (ví dụ const url = new URL("https://stackoverflow.com")), bạn có thể đặt chuỗi truy vấn của nó url.search = new URLSearchParams({foo: "bar"})hoặcurl.searchParams.append("foo", "bar")
Miguel Pynto

Lưu ý rằng TS sẽ cảnh báo về việc sử dụng một vật thể đơn giản, nhưng dù sao nó cũng hoạt động tốt
Vadorequest

@pomber Có ý tưởng hay nào về việc lọc những mục không xác định đó không?
Dan Gayle

53

Điều này không trả lời trực tiếp câu hỏi của bạn, nhưng đây là một hàm chung sẽ tạo một URL chứa các tham số chuỗi truy vấn. Các tham số (tên và giá trị) được thoát an toàn để đưa vào 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

1
Có bất kỳ chức năng tích hợp nào tương tự như chức năng này trong một trong các khung javascript phổ biến như jquery, mootools, v.v ... không?
Samuel

Một giải pháp JavaScript gốc mạnh mẽ hơn có tại stackoverflow.com/a/1714899/1269037
Dan Dascalescu

Triển khai kỳ lạ nhất từ ​​trước đến nay, tại sao bạn cần khởi tạo một new Arraylúc bạn thực sự sử dụng nó như một đối tượng? o, O
Umut Sirin

@UmutSirin Lol yeah Tôi không biết nhiều về Javascript vào thời điểm đó. xD Tôi nghĩ rằng tôi đã coi nó như một mảng PHP. Hãy tái cấu trúc nếu bạn muốn.
Michael

@Michael Haha, vâng. Tôi vừa gửi một bản chỉnh sửa. Cảm ơn bạn đã trả lời!
Umut Sirin

22

Với jQuery bạn có thể làm điều này bằng cách $.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"

17

ES2017 (ES8)

Việc sử dụng Object.entries(), trả về một mảng các [key, value]cặp đối tượng . Ví dụ, cho {a: 1, b: 2}nó sẽ trở lại [['a', 1], ['b', 2]]. Nó không chỉ được hỗ trợ (và sẽ không) bởi IE.

Mã số:

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

Thí dụ:

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

Kết quả:

"name=John&gender=male"

Thay vào đó, hãy sử dụng url.spec.whatwg.org/#urlsearchparams
Boris

10

Không, tôi không nghĩ JavaScript tiêu chuẩn được tích hợp sẵn, nhưng Prototype JS có chức năng đó (chắc chắn hầu hết các khung công tác JS khác cũng vậy, nhưng tôi không biết chúng), họ gọi nó là tuần tự hóa .

Tôi có thể giới thiệu Prototype JS, nó hoạt động khá ổn. Hạn chế duy nhất tôi thực sự nhận thấy đó là kích thước (vài trăm kb) và phạm vi (rất nhiều mã cho ajax, dom, v.v.). Do đó, nếu bạn chỉ muốn một trình tuần tự hóa biểu mẫu thì quá mức cần thiết và nói đúng ra nếu bạn chỉ muốn chức năng Ajax của nó (chủ yếu là những gì tôi đã sử dụng nó) thì đó là quá mức cần thiết. Trừ khi bạn cẩn thận, bạn có thể thấy rằng nó thực hiện quá nhiều "ma thuật" (như mở rộng mọi phần tử dom mà nó chạm vào bằng các hàm Prototype JS chỉ để tìm các phần tử) làm cho nó chậm trong các trường hợp cực đoan.


Chỉ tự hỏi nếu có bất cứ điều gì tích hợp. Có vẻ như nên có. Tôi ghét nguyên mẫu, nhưng tôi không chống lại bạn :)

Khi JavaScript được thiết kế, Ajax chưa được phát hiện, do đó phân tích cú pháp một biểu mẫu chỉ để lấy chuỗi truy vấn (mà nó sẽ tự tạo khi gửi) có lẽ không có ý nghĩa gì nhiều. Ngày nay, khó khăn ... Btw, so với script.aculo.us, nguyên mẫu là tốt . :)
Stein G. Strindhaug

10

chuỗi truy vấn có thể giúp đỡ.

Vì vậy, bạn có thể

const querystring = require('querystring')

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

3
Đối với các ứng dụng lối vào, bạn cũng có thể xem xét npmjs.com/package/qs
Robert Pankowecki

@RobertPankowecki, vâng, qs tốt hơn và đã có trong kho vũ khí của tôi, chúc mừng!
ImLeo

6

Nếu bạn không muốn sử dụng thư viện, phần này sẽ bao gồm hầu hết / tất cả các loại phần tử biểu mẫu giống nhau.

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('&');
}

Cảm ơn! Tôi chỉ phải đối mặt với cùng một vấn đề như poster ban đầu, và chức năng của bạn là chính xác những gì tôi cần.
dagw

4

Bạn thực sự không cần một hình thức để làm điều này với Prototype. Chỉ cần sử dụng hàm Object.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'

4
Cấp, bạn đã trả lời gần 10 năm trước, nhưng mã này hiện không được chấp nhận.
SEoF

4

Bạn có thể làm điều đó ngày nay có FormDataURLSearchParamskhông cần phải lặp đi lặp lại bất cứ điều gì.

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

Các trình duyệt cũ hơn sẽ cần một polyfill, mặc dù.


3

Tôi không hoàn toàn chắc chắn về bản thân mình, tôi nhớ rằng đã thấy jQuery đã làm điều đó ở một mức độ nào đó, nhưng nó hoàn toàn không xử lý các bản ghi phân cấp, chứ đừng nói theo cách thân thiện với php.

Một điều tôi biết chắc chắn, là khi xây dựng URL và dán sản phẩm vào dom, đừng chỉ sử dụng keo dán chuỗi để làm điều đó, hoặc bạn sẽ tự mở một công cụ ngắt trang tiện dụng.

Chẳng hạn, một số phần mềm quảng cáo nối tiếp chuỗi phiên bản từ bất cứ thứ gì chạy flash của bạn. Điều này tốt khi nó tuân theo chuỗi đơn giản chung chung, tuy nhiên, điều đó rất ngây thơ và làm nổ tung một mớ hỗn độn cho những người đã cài đặt Gnash, vì chuỗi phiên bản của gnash tình cờ chứa một giấy phép bản quyền GPL đầy đủ, hoàn chỉnh với các URL và <a href> thẻ. Sử dụng điều này trong trình tạo quảng cáo keo dán chuỗi của bạn, kết quả là trang sẽ mở ra và có HTML mất cân bằng xuất hiện trong dom.

Noi dung chinh cua cau chuyen:

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

Không phải:

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

Google cần học thủ thuật này. Tôi đã cố gắng báo cáo vấn đề, họ dường như không quan tâm.


Ngay trên. Document.write là như vậy 1995, dù sao.

2

Như Stein nói, bạn có thể sử dụng thư viện javascript nguyên mẫu từ http://www.prototypejs.org . Bao gồm cả JS và nó rất đơn giản sau đó, $('formName').serialize()sẽ trả về những gì bạn muốn!



2

Có thể là một chút dư thừa nhưng cách sạch nhất tôi tìm thấy dựa trên một số câu trả lời ở đây:

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,
})

Nguồn


1

Những câu trả lời này rất hữu ích, nhưng tôi muốn thêm một câu trả lời khác, có thể giúp bạn xây dựng URL đầy đủ. Điều này có thể giúp bạn concat cơ sở url, path, hashparameters.

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

Bạn có thể tải xuống qua npm https://www.npmjs.com/package/build-url

Bản giới thiệu:

;(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);


1

Tôi biết đây là câu trả lời rất muộn nhưng hoạt động rất tốt ...

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

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

lưu ý: object.entries sẽ trả về khóa, cặp giá trị

đầu ra từ dòng trên sẽ là a = a & b = b

Hy vọng nó sẽ giúp được ai đó.

Mã hóa hạnh phúc ...


0

Có lẽ là quá muộn để trả lời câu hỏi của bạn.
Tôi có cùng một câu hỏi và tôi không muốn tiếp tục nối các chuỗi để tạo URL. Vì vậy, tôi bắt đầu sử dụng $ .param như techhouse giải thích.
Tôi cũng tìm thấy thư viện URI.js tạo URL dễ dàng cho bạn. Có một số ví dụ sẽ giúp bạn: URI.js Documentation .
Đây là một trong số chúng:

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"]);`

0

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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.