Как построить строку запроса с Javascript


168

Просто интересно, есть ли что-нибудь встроенное в Javascript, которое может принимать форму и возвращать параметры запроса, например: "var1=value&var2=value2&arr[]=foo&arr[]=bar..."

Я думал об этом годами.


1
К вашему сведению: phpjs.org/functions/http_build_query

Ответы:


-25

Я пытался найти ответ на этот вопрос некоторое время назад, но в итоге я написал свою собственную функцию, которая извлекает значения из формы.

это не идеально, но это соответствует моим потребностям.

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 возвращает (ключ -> значение) отображение параметров. вход является элементом формы (элемент DOM)

Он не обрабатывает поля, которые допускают множественный выбор.


44
Это только у меня так или не отвечает на вопрос вообще? Он просил строку запроса, а не сопоставленный массив.
Джейк Уилсон

2
@JakeWilson Да, этот ответ только наполовину отвечает на вопрос. Массив все еще должен попасть в формат строки запроса.
Хатч Мур

9
Вау, я тогда был нубом в JS. Используется new Array()для инициализации словаря. Но опять же, код выглядит намного чище, чем та чушь, которую я бы написал в эти дни!
hasen

2
@ Может быть, вы бы отредактировали этот ответ или удалили его? Каждый раз, когда я прокручиваю к нему, у него появляется все больше и больше отрицательных голосов = -D (я даже помню время, когда оно имело положительное соотношение ...)
Klesun

1
@ArturKlesun да, нет. Мне все равно Вы можете попробовать попросить человека, который задал вопрос, принять этот ответ.
Hasen

220

Обновление 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]);})

8
Лучшее решение, которое я видел, - очень чистое и лаконичное. Несколько предостережений. 1) в .map () должны кодироваться как k, так и params [k], например, encodeURIComponent (k) и encodeURIComponent (params [k]). 2) Вам разрешено иметь более одного экземпляра именованного параметра в строке запроса. Если вы хотите эту возможность, вам придется использовать массив вместо объекта (большинству приложений это не нужно или не нужно).
Джон Дейган

9
3) Не все браузеры будут поддерживать синтаксис функции стрелок (для этого требуется ES5). Если вы хотите поддерживать все браузеры (и кодировать части), замените вышеуказанный .map () на .map (function (k) {return encodeURIComponent (k) + '=' + encodeURIComponent (params [k]);})
Джон Дейган

1
Прекрасный. Действительно красиво.
Микко Охтамаа

9
«не хватит jquery»
Евгений Панков

1
@ user1738579 Я отредактировал ответ, чтобы также включить твой пример для не-ES5.
Тейлор Эдмистон

135

Если вы используете JQuery, вы можете проверить jQuery.param() http://api.jquery.com/jQuery.param/

Пример:

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

13
Это на самом деле правильный ответ! Строка запроса для формы $.param($('#myform').serializeArray()).
Джесси

7
@Jesse, это будет тот же результат, что и:$('#myform').serialize()
Кливер

95
jQuery !== JavaScript
gphilip

14
@gphilip Ну вот почему я начал ответ с "Если вы используете jQuery ...". В противном случае, если вы хотите реализовать его в vanilla JS, вы можете проверить реализацию jQuery.param()здесь github.com/jquery/jquery/blob/master/src/serialize.js :)
Клемен Тушар

2
В отличие от моего ответа, этот поддерживает вложенные объекты, такие какsomeStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2
Klesun

113

API URLSearchParams доступен во всех современных браузерах. Например:

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


3
Лучший ответ здесь IMO. Просто чтобы добавить к нему, вы можете сделать params.append(key, value)позже для добавления новых параметров поиска в более сложных сценариях.
Минвэй Чжан

4
Обратите внимание, что неопределенные и нулевые значения включены в последнюю строку:x=null&y=undefined
pomber

2
Кроме того, если у вас уже есть объект URL (например const url = new URL("https://stackoverflow.com")), вы можете установить его строки запроса url.search = new URLSearchParams({foo: "bar"})илиurl.searchParams.append("foo", "bar")
Мигель Пинто

Обратите внимание, что TS предупредит об использовании простого объекта, но, тем не менее, работает нормально
Vadorequest

@pomber Любые хорошие идеи по фильтрации этих неопределенных элементов?
Дэн Гейл

53

Это не дает прямого ответа на ваш вопрос, но вот общая функция, которая создаст 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

1
Есть ли встроенная функция, подобная этой, в одной из популярных фреймворков javascript, таких как jquery, mootools и т. Д ...?
Самуил

Более надежное решение на нативном JavaScript размещено на stackoverflow.com/a/1714899/1269037
Дан Даскалеску

Самая странная реализация, почему вам нужно инициализировать то new Arrayвремя, когда вы фактически используете ее как объект? о, о
Умут Сирин

@ UmutSirin Lol Да, я не очень много знал о Javascript в то время. xD Я думаю, что рассматривал это как массив PHP. Не стесняйтесь рефакторинг, если хотите.
Майкл

@ Майкл Хаха, да. Я только что отправил редактирование. Спасибо за ответ!
Умут Сирин

22

С помощью 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"

17

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"


10

Нет, я не думаю, что в стандартном JavaScript это встроено, но в Prototype JS есть эта функция (конечно, в большинстве других сред JS тоже есть, но я их не знаю), они называют ее сериализацией. .

Я могу порекомендовать Prototype JS, он работает вполне нормально. Единственный недостаток, который я действительно заметил, это его размер (несколько сотен килобайт) и объем (много кода для ajax, dom и т. Д.). Таким образом, если вам нужен только сериализатор форм, это излишне, и, строго говоря, если вы хотите, чтобы это была только функциональность Ajax (в основном это то, для чего я его использовал), это излишне. Если вы не будете осторожны, вы можете обнаружить, что он делает слишком много «магии» (например, расширяет каждый элемент dom, которого он касается, с помощью функций Prototype JS просто для поиска элементов), делая его медленным в крайних случаях.


Просто интересно, есть ли что-нибудь встроенное. Похоже, должно быть. Я ненавижу прототип, но я не против этого :)

Когда разрабатывался JavaScript, Ajax еще не был обнаружен, поэтому анализ формы только для того, чтобы получить строку запроса (которая будет создана при отправке), вероятно, не имел особого смысла. Сегодня это получается, жестко ... Кстати, по сравнению с script.aculo.us, прототип хорош . :)
Штейн Г. Стриндхауг


6

Если вы не хотите использовать библиотеку, это должно охватывать большинство / все одинаковые типы элементов формы.

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

Спасибо! Я столкнулся с той же проблемой, что и оригинальный постер, и ваша функция была именно тем, что мне было нужно.
dagw

4

Вам на самом деле не нужна форма, чтобы сделать это с Prototype. Просто используйте функцию 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
Конечно, вы ответили почти 10 лет назад, но этот код устарел.
SEoF

4

Вы можете сделать это в настоящее время с FormDataи URLSearchParamsбез необходимости зацикливаться на чем-либо.

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

Тем не менее, в старых браузерах потребуется полифилл.


3

Я не совсем уверен, я помню, что jQuery делал это до некоторой степени, но он вообще не обрабатывает иерархические записи, не говоря уже о php-дружественном способе.

Я точно знаю одну вещь: когда вы создаете URL-адреса и вставляете продукт в dom, не просто используйте для этого строковый клей, иначе вы откроете себя для удобного средства разбиения страниц.

Например, определенное рекламное программное обеспечение вставляет строку версии из того, что запускает вашу флеш-память. Это хорошо, когда он использует общую простую строку, но, тем не менее, это очень наивно и взрывается в смущающем беспорядке для людей, которые установили Gnash, поскольку строка версии gnash'а содержит полную лицензию на авторские права GPL с URL-адресами. и <a href> теги. Использование этого в генераторе рекламодателя со связыванием строк приводит к тому, что страница открывается, и в домене появляется неуравновешенный HTML.

Мораль этой истории:

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

Не:

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

Google нужно научиться этому трюку. Я пытался сообщить о проблеме, они, кажется, не волнует.


Право на. В любом случае Document.write - это 1995 год.

2

Как говорит Стейн, вы можете использовать библиотеку прототипов javascript с http://www.prototypejs.org . Включите JS, и это очень просто, $('formName').serialize()вернет, что вы хотите!



2

Может быть, немного излишним, но самый чистый способ, который я нашел, основывается на некоторых из ответов здесь:

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

Источник


1

Эти ответы очень полезны, но я хочу добавить еще один ответ, который может помочь вам создать полный URL. Это может помочь вам CONCAT базы url, path, hashи parameters.

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


1

Я знаю, что это очень поздний ответ, но работает очень хорошо ...

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

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

примечание: object.entries вернет ключ, пары значений

Выходная информация из вышеуказанной строки будет a = a & b = b

Надеюсь, это поможет кому-то.

Удачного кодирования ...


0

Возможно, уже слишком поздно, чтобы ответить на ваш вопрос.
У меня был тот же вопрос, и я не хотел добавлять строки для создания URL. Итак, я начал использовать $ .param, как объяснил 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"]);`

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>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.