Jak zbudować ciąg zapytania za pomocą JavaScript

Odpowiedzi:

-24

Jakiś czas temu próbowałem znaleźć odpowiedź na to pytanie, ale ostatecznie napisałem własną funkcję, która wyodrębnia wartości z formularza.

nie jest idealny, ale pasuje do moich potrzeb.

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 zwraca mapowanie parametrów (klucz -> wartość). dane wejściowe to element formularza (element DOM)

Nie obsługuje pól, które umożliwiają wielokrotny wybór.

hasen
źródło
44
Czy to tylko ja, czy to w ogóle nie odpowiada na pytanie? Pytał o ciąg zapytania, a nie o zmapowaną tablicę.
Jake Wilson
2
@JakeWilson Tak, ta odpowiedź tylko w połowie odpowiada na pytanie. Tablica nadal musi przejść do formatu ciągu zapytania.
Hutch Moore
9
wow, musiałem być wtedy noobem w JS. Użycie new Array()do inicjalizacji słownika. Ale z drugiej strony, kod wygląda o wiele czyściej niż niektóre bzdury, które napisałbym ostatnio!
hasen
2
@hasen może rozważyłbyś edytowanie tej odpowiedzi lub, hm, cóż, usunięcie jej? Za każdym razem, gdy do niego przewijam, ma coraz więcej głosów przeciwnych = -D (pamiętam nawet czas, kiedy miał pozytywny stosunek ...)
Klesun
1
@ArturKlesun tak, nie. Nie obchodzi mnie to. Możesz spróbować poprosić osobę, która zadała pytanie, o wycofanie tej odpowiedzi.
hasen
220

Aktualizacja 2k20: użyj rozwiązania Josha z URLSearchParams.toString () .

Stara odpowiedź:


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

W przypadku przeglądarek, które nie obsługują składni funkcji strzałek, która wymaga ES5, zmień .map...wiersz na

    .map(function(k) {return esc(k) + '=' + esc(params[k]);})
Klesun
źródło
8
Najlepsze rozwiązanie, jakie do tej pory widziałem - bardzo przejrzyste i zwięzłe. Jednak kilka zastrzeżeń. 1) w .map () należy zakodować k i params [k], np. EncodeURIComponent (k) i encodeURIComponent (params [k]). 2) Możesz mieć więcej niż jedno wystąpienie nazwanego parametru w ciągu zapytania. Jeśli chcesz mieć taką możliwość, będziesz musiał użyć tablicy zamiast obiektu (większość aplikacji tego nie chce ani nie potrzebuje).
John Deighan
9
3) Nie wszystkie przeglądarki obsługują składnię funkcji strzałek (wymaga to ES5). Jeśli chcesz obsługiwać wszystkie przeglądarki (i zakodować części), zamień powyższe .map () na .map (function (k) {return encodeURIComponent (k) + '=' + encodeURIComponent (params [k]);})
John Deighan
1
Piękny. Naprawdę piękny.
Mikko Ohtamaa
9
„za mało jquery”
Eugene Pankov,
1
@ user1738579 Zmieniłem odpowiedź, aby uwzględnić również Twój przykład dla wersji innej niż ES5.
Taylor Edmiston
134

Jeśli używasz jQuery, możesz sprawdzić jQuery.param() http://api.jquery.com/jQuery.param/

Przykład:

var params = {
    parameter1: 'value1',
    parameter2: 'value2',
    parameter3: 'value3' 
};
var query = $.param(params);
document.write(query);
Klemen Tušar
źródło
13
To jest właściwie prawidłowa odpowiedź! Ciąg zapytania dla formularza to $.param($('#myform').serializeArray()).
Jesse
7
@Jesse, to byłby taki sam wynik jak:$('#myform').serialize()
cleaver
94
jQuery !== JavaScript
gphilip
14
@gphilip Cóż, dlatego zacząłem odpowiedź od „Jeśli używasz jQuery ...”. W przeciwnym razie, jeśli chcesz zaimplementować go w waniliowym JS, możesz sprawdzić implementację jQuery.param()tutaj github.com/jquery/jquery/blob/master/src/serialize.js :)
Klemen Tušar
2
W przeciwieństwie do mojej odpowiedzi, ten obsługuje obiekty zagnieżdżone, takie jaksomeStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2
Klesun,
113

Interfejs API URLSearchParams jest dostępny we wszystkich nowoczesnych przeglądarkach. Na przykład:

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

Josh
źródło
3
Najlepsza odpowiedź tutaj imo. Aby to dodać, możesz params.append(key, value)później dodać nowe parametry wyszukiwania w bardziej skomplikowanych scenariuszach.
Mingwei Zhang
4
Zwróć uwagę, że wartości niezdefiniowane i null są zawarte w końcowym ciągu:x=null&y=undefined
pomber
2
Ponadto, jeśli masz już obiekt URL (na przykład const url = new URL("https://stackoverflow.com")), możesz ustawić jego ciągi zapytań url.search = new URLSearchParams({foo: "bar"})luburl.searchParams.append("foo", "bar")
Miguel Pynto
Zauważ, że TS ostrzega przed używaniem zwykłego obiektu, ale mimo to działa dobrze
Vadorequest
@pomber Jakieś dobre pomysły na odfiltrowywanie tych niezdefiniowanych elementów?
Dan Gayle
53

To nie jest bezpośrednią odpowiedzią na twoje pytanie, ale oto ogólna funkcja, która utworzy adres URL zawierający parametry ciągu zapytania. Parametry (nazwy i wartości) są chronione za pomocą znaków zmiany znaczenia w celu umieszczenia ich w adresie 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
Michael
źródło
1
Czy jest jakaś wbudowana funkcja podobna do tej w jednym z popularnych frameworków javascript, takich jak jquery, mootools itp ...?
Samuel
Bardziej niezawodne natywne rozwiązanie JavaScript jest dostępne pod adresem stackoverflow.com/a/1714899/1269037
Dan Dascalescu
Najdziwniejsza implementacja w historii, dlaczego musisz przez jakiś new Arrayczas inicjować, kiedy faktycznie używasz jej jako obiektu? o, O
Umut Sirin
@UmutSirin Lol yeah Nie wiedziałem wtedy zbyt wiele o Javascript. xD Myślę, że traktowałem to jak tablicę PHP. Jeśli chcesz, możesz dokonać refaktoryzacji.
Michael
@Michael Haha, tak. Właśnie wysłałem edycję. Dziękuję za Twoją odpowiedź!
Umut Sirin
22

Dzięki jQuery możesz to zrobić przez $.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"
manish_s
źródło
17

ES2017 (ES8)

Wykorzystanie Object.entries(), które zwraca tablicę [key, value]par obiektów. Na przykład, {a: 1, b: 2}ponieważ powróci[['a', 1], ['b', 2]] . Nie jest obsługiwany (i nie będzie) tylko przez IE.

Kod:

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

Przykład:

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

Wynik:

"name=John&gender=male"
Przemek
źródło
10

Nie, nie sądzę, że standardowy JavaScript ma to wbudowane, ale Prototype JS ma tę funkcję (z pewnością większość innych frameworków JS też ma, ale ich nie znam), nazywają to serializacją .

Mogę polecić Prototype JS, działa całkiem nieźle. Jedyną wadą, jaką naprawdę zauważyłem, jest rozmiar (kilkaset kb) i zasięg (dużo kodu dla AJAX, DOM, itp.). Tak więc, jeśli chcesz tylko serializatora formularzy, jest to przesada, a ściśle mówiąc, jeśli chcesz mieć tylko funkcjonalność Ajax (do której głównie służyłem), to przesada. O ile nie jesteś ostrożny, może się okazać, że robi to trochę za dużo „magii” (jak na przykład rozszerzanie każdego elementu dom, którego dotyka za pomocą funkcji Prototype JS tylko po to, by znaleźć elementy), spowalniając go w skrajnych przypadkach.

Stein G. Strindhaug
źródło
Zastanawiam się, czy jest coś wbudowanego. Wydaje się, że powinno być. Nienawidzę prototypów, ale nie mam tego przeciwko tobie :)
Kiedy projektowano JavaScript, Ajax nie został jeszcze odkryty, dlatego analizowanie formularza tylko po to, aby uzyskać kwerendę (że sam się utworzy po przesłaniu) prawdopodobnie nie miało większego sensu. Dziś jest ciężko ... Przy okazji, w porównaniu do script.aculo.us, prototyp jest fajny . :)
Stein G. Strindhaug
10

Querystring może pomóc.

Więc możesz

const querystring = require('querystring')

url += '?' + querystring.stringify(parameters)
ImLeo
źródło
3
W przypadku aplikacji frontendowych możesz również rozważyć npmjs.com/package/qs
Robert Pankowecki
@RobertPankowecki, tak, qs jest lepsze i już w moim arsenale, pozdrawiam!
ImLeo
6

Jeśli nie chcesz korzystać z biblioteki, powinno to obejmować większość / wszystkie te same typy elementów formularza.

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('&');
}
Jonathan Lonowski
źródło
Dzięki! Właśnie miałem ten sam problem, co na oryginalnym plakacie, a twoja funkcja była dokładnie tym, czego potrzebowałem.
dagw
4

W rzeczywistości nie potrzebujesz formularza, aby to zrobić z Prototype. Po prostu użyj funkcji 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'
Thibaut Barrère
źródło
4
To prawda, że ​​odpowiedziałeś prawie 10 lat temu, ale ten kod jest obecnie przestarzały.
SEoF
4

W dzisiejszych czasach możesz to zrobić z FormDatai URLSearchParamsbez potrzeby zapętlania wszystkiego.

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

Starsze przeglądarki będą jednak potrzebowały wypełnienia.

Björn Tantau
źródło
3

Sam nie jestem do końca pewien, pamiętam, że widziałem, jak jQuery zrobił to w pewnym stopniu, ale w ogóle nie obsługuje rekordów hierarchicznych, nie mówiąc już w sposób przyjazny dla php.

Jedną rzeczą, którą wiem na pewno, jest to, że podczas budowania adresów URL i wklejania produktu do domeny nie używaj do tego zwykłego kleju, bo otworzysz się na poręczny program do łamania stron.

Na przykład, niektóre programy reklamowe wstawiają ciąg znaków wersji z tego, co uruchamia twój flash. To jest w porządku, gdy jego ogólny prosty ciąg adobes, ale jest to bardzo naiwne i wybucha w zawstydzającym bałaganie dla ludzi, którzy zainstalowali Gnash, ponieważ ciąg wersji gnash zawiera pełną licencję praw autorskich GPL, wraz z adresami URL i <a href>. Użycie tego w generatorze reklamodawców typu string-glue powoduje otwarcie strony i wyświetlenie niezrównoważonego kodu HTML w domenie.

Morał tej historii:

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

Nie:

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

Google musi nauczyć się tej sztuczki. Próbowałem zgłosić problem, wydaje się, że ich to nie obchodzi.

Kent Fredric
źródło
Tak jest. Document.write jest tak 1995, w każdym razie.
2

Jak mówi Stein, możesz skorzystać z prototypowej biblioteki javascript ze strony http://www.prototypejs.org . Dołącz JS i to jest bardzo proste, $('formName').serialize()zwróci to, co chcesz!

Shyam
źródło
2

Może być trochę zbędny, ale najczystszy sposób, jaki znalazłem, oparty na niektórych odpowiedziach tutaj:

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

Źródło

David Pascoal
źródło
1

Te odpowiedzi są bardzo pomocne, ale chcę dodać kolejną odpowiedź, która może pomóc w utworzeniu pełnego adresu URL. To może pomóc concat podstawy url, path, hashi parameters.

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

Możesz pobrać przez npm https://www.npmjs.com/package/build-url

Próbny:

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

Hien Nguyen
źródło
1

Wiem, że to bardzo późna odpowiedź, ale działa bardzo dobrze ...

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

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

uwaga: obiekt.entries zwróci pary klucz, wartość

wyjście z powyższej linii będzie a = a & b = b

Mam nadzieję, że to komuś pomoże.

Miłego kodowania ...

ajaykumar mp
źródło
0

Prawdopodobnie jest już za późno, aby odpowiedzieć na Twoje pytanie.
Miałem to samo pytanie i nie lubiłem nadal dołączać ciągów znaków, aby utworzyć adres URL. Więc zacząłem używać $ .param jak techhouse wyjaśnione.
Znalazłem również bibliotekę URI.js, która łatwo tworzy dla Ciebie adresy URL. Istnieje kilka przykładów, które pomogą Ci: URI.js Dokumentacja .
Oto jeden z nich:

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"]);`
SaraNa
źródło
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>

Bashirpour
źródło