Як побудувати рядок запиту за допомогою Javascript


167

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

Я дивувався цьому років.



Відповіді:


-24

Я деякий час тому намагався шукати відповідь на це питання, але я закінчив писати власну функцію, яка витягує значення з форми ..

це не ідеально, але відповідає моїм потребам.

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
@hasen, можливо, ви б подумали відредагувати цю відповідь або, гм, ну, видалити її? Щоразу, коли я прокручую до нього, є все більше зворотних подій (я навіть пам’ятаю час, коли він мав позитивне співвідношення ...)
Клесун

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, так і парами [k], наприклад encodeURIComponent (k) та encodeURIComponent (params [k]). 2) Ви можете мати більше одного примірника названого параметра в рядку запиту. Якщо вам потрібна ця можливість, вам доведеться використовувати масив замість об'єкта (більшість програм цього не хочуть і не потребують).
Джон Дейган

9
3) Не всі браузери підтримуватимуть синтаксис функції стрілок (для цього потрібен ES5). Якщо ви хочете підтримувати всі веб-переглядачі (і кодувати їх частини), замініть вище.
Джон Дейган

1
Гарний. Воістину красива.
Мікко Охтамаа

9
"недостатньо jquery"
Євген Панков

1
@ user1738579 Я відредагував відповідь, щоб також включити ваш приклад для не-ES5.
Тейлор Едмістон

134

Якщо ви використовуєте 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 ...". В іншому випадку, якщо ви хочете реалізувати його у ванільному 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)пізніше додати нові параметри пошуку у складніших сценаріях.
Mingwei Zhang

4
Зауважте, що невизначені та нульові значення включені у заключний рядок:x=null&y=undefined
помбер

2
Також якщо у вас вже є об’єкт URL (наприклад const url = new URL("https://stackoverflow.com")), ви можете встановити його рядки запиту url.search = new URLSearchParams({foo: "bar"})абоurl.searchParams.append("foo", "bar")
Miguel Pynto

Зауважте, що 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 для poplars, як jquery, mootools тощо?
Самуїл

Більш надійне рішення нативного JavaScript знаходиться в stackoverflow.com/a/1714899/1269037
Dan Dăscălescu

Найцікавіша реалізація будь-коли, чому вам потрібно ініціалізувати деякий new Arrayчас, коли ви насправді використовуєте її як об’єкт? o, O
Умут Сірін

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

@Michael Haha, так. Я щойно надіслав правку. Дякую за відповідь!
Умут Сірін

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"

Використовуйте натомість url.spec.whatwg.org/#urlsearchparams
Борис

10

Ні, я не думаю, що в стандартному JavaScript є вбудований, але прототип JS має таку функцію (напевно, більшість інших фреймворків JS теж є, але я їх не знаю), вони називають це серіалізацією .

Я можу рекомендувати прототип JS, він працює цілком нормально. Єдиний недолік, який я дійсно помітив, це його розмір (кілька сотень кбіт) та масштабність (багато коду для ajax, dom тощо). Таким чином, якщо ви хочете лише серіалізатор форми, це надмірність, а якщо ви хочете, що це лише функціональність Ajax (для чого я в основному це використовував), це буде надмірне вбивство. Якщо ви не обережні, ви можете виявити, що це робить занадто багато "магії" (наприклад, розширення кожного елемента dom, який він торкається за допомогою прототипу JS функцій, щоб знайти елементи), що робить його повільним у надзвичайних випадках.


Просто цікаво, чи є щось вбудоване. Здається, що має бути. Я ненавиджу прототип, але я не дотримуюся цього проти вас :)

Коли був розроблений JavaScript, Ajax ще не був знайдений, тому для розбору форми просто для отримання запиту (що він буде створювати сам при надсиланні), мабуть, мало особливого сенсу. Сьогодні це, важко ... Btw, порівняно з 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

Насправді вам не потрібна форма для цього з прототипом. Просто використовуйте функцію 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-адреси та вставляти виріб у дому, не використовуйте для цього лише рядок-клей, інакше ви відкриєте себе зручним вимикачем сторінок.

Наприклад, певне рекламне програмне забезпечення вбудовує рядок версії з будь-якого запуску флеш-версії. Це добре, коли його обоє простий рядок, але це дуже наївно, і це збентежило людей, які встановили Gnash, оскільки рядок версії gnash'es має містити повноцінні ліцензії на авторські права 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"]);`

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.