วิธีสร้างสตริงข้อความค้นหาด้วย 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
เป็นเพียงฉันหรือไม่ตอบคำถามเลย? เขาขอสตริงข้อความค้นหาไม่ใช่อาร์เรย์ที่แมป
Jake Wilson

2
@ JakeWilson ใช่คำตอบนี้เพียงครึ่งเดียวตอบคำถาม อาร์เรย์ยังคงต้องได้รับในรูปแบบสตริงแบบสอบถาม
ฮัทช์มัวร์

9
ว้าวฉันคงเคยเป็น noob ที่ JS มาก่อนแล้ว ใช้new Array()เพื่อเริ่มต้นพจนานุกรม แต่อีกครั้งรหัสดูสะอาดกว่าอึฉันจะเขียนวันนี้!
Hasen

2
@hasen คุณอาจลองแก้ไขคำตอบนี้หรือเอาล่ะลบออกไหม? มันมี downvotes มากขึ้นทุกครั้งที่ฉันเลื่อนไปที่ = - D (ฉันยังจำเวลาที่มีอัตราส่วนเป็นบวก ... )
Klesun

1
@ ArturKlesun ใช่แล้ว ฉันไม่สนใจ คุณสามารถลองถามคนที่ถามคำถามเพื่อยกเลิกคำตอบนี้
hasen

220

อัปเดต 2k20: ใช้ของ Joshวิธีการแก้ปัญหาที่มี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) คุณได้รับอนุญาตให้มีมากกว่าหนึ่งอินสแตนซ์ของพารามิเตอร์ที่มีชื่อในสตริงแบบสอบถาม หากคุณต้องการความสามารถนั้นคุณจะต้องใช้อาร์เรย์แทนวัตถุ (แอปพลิเคชันส่วนใหญ่ไม่ต้องการหรือต้องการ)
John Deighan

9
3) ไม่ใช่ทุกเบราว์เซอร์ที่จะรองรับไวยากรณ์ของฟังก์ชั่นลูกศร (ต้องใช้ ES5) หากคุณต้องการสนับสนุนเบราว์เซอร์ทั้งหมด (และเข้ารหัสส่วน) แทนที่. map ข้างต้นด้วย. map (function (k) {return encodeURIComponent (k) + '=' + encodeURIComponent (params [k]);}
John Deighan

1
สวย. สวยอย่างแท้จริง
Mikko Ohtamaa

9
"jquery ไม่เพียงพอ"
Eugene Pankov

1
@ user1738579 ฉันแก้ไขคำตอบเพื่อรวมตัวอย่างของคุณสำหรับที่ไม่ใช่ ES5
Taylor Edmiston

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())สตริงแบบสอบถามสำหรับรูปแบบคือ
Jesse

7
@Jesse นั้นจะเป็นผลเช่นเดียวกับ:$('#myform').serialize()

95
jQuery !== JavaScript
gphilip

14
@ gphilip นั่นเป็นสาเหตุที่ฉันเริ่มตอบสนองด้วย "หากคุณใช้ jQuery ... " มิฉะนั้นถ้าคุณต้องการที่จะใช้มันในวานิลลา JS คุณสามารถตรวจสอบการดำเนินงานของjQuery.param()ที่นี่github.com/jquery/jquery/blob/master/src/serialize.js :)
Klemen Tusar

2
ซึ่งแตกต่างจากคำตอบของฉันคนนี้สนับสนุนวัตถุที่ซ้อนกันเช่นsomeStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2
Klesun

113

URLSearchParams APIมีอยู่ในเบราว์เซอร์ที่ทันสมัยทั้งหมด ตัวอย่างเช่น:

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)ภายหลังเพื่อเพิ่ม params การค้นหาใหม่ในสถานการณ์ที่ซับซ้อนมากขึ้น
Mingwei Zhang

4
โปรดทราบว่าค่าที่ไม่ได้กำหนดและค่า null จะรวมอยู่ในสตริงสุดท้าย: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")
Miguel Pynto

โปรดทราบว่า TS จะเตือนเกี่ยวกับการใช้วัตถุธรรมดา แต่ก็ใช้งานได้ดี
Vadorequest

@pomber มีความคิดที่ดีเกี่ยวกับการกรองรายการที่ไม่ได้กำหนดเหล่านั้นออกหรือไม่
Dan Gayle

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
มีฟังก์ชั่นในตัวที่คล้ายกับหนึ่งในเฟรมเวิร์กจาวาสคริปต์ยอดนิยมอย่าง jquery, mootools ฯลฯ หรือไม่?
ซามูเอล

โซลูชัน JavaScript แบบเนทีฟที่แข็งแกร่งกว่านั้นคือstackoverflow.com/a/1714899/1269037
Dan Dascalescu

การนำไปใช้ที่แปลกประหลาดที่สุดทำไมคุณต้องเริ่มต้นnew Arrayในขณะที่คุณใช้มันเป็นวัตถุจริงๆ o, O
Umut Sirin

@UmutSirin Lol ใช่ฉันไม่รู้เกี่ยวกับ Javascript มากในเวลานั้น xD ฉันคิดว่าฉันกำลังรักษามันเหมือนอาร์เรย์ PHP อย่าลังเลที่จะ refactor หากคุณต้องการ
Michael

@Michael Haha ใช่ ฉันเพิ่งส่งการแก้ไข ขอบคุณสำหรับคำตอบ!
Umut Sirin

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แทน
Boris

10

ไม่ฉันไม่คิดว่ามาตรฐาน JavaScript ได้ว่าในตัว แต่ต้นแบบ JS มีฟังก์ชั่น (JS แน่นอนกรอบอื่น ๆ ส่วนใหญ่จะมีมากเกินไป แต่ผมไม่ทราบว่าพวกเขา) พวกเขาเรียกว่าเป็นอันดับ

ฉันขอแนะนำ Prototype JS มันใช้งานได้ดี ข้อเสียเปรียบเพียงอย่างเดียวที่ฉันสังเกตเห็นมันคือขนาด (ไม่กี่ร้อย kb) และขอบเขต (มีโค้ดจำนวนมากสำหรับ ajax, dom และอื่น ๆ ) ดังนั้นถ้าคุณต้องการ serializer แบบฟอร์มมัน overkill และพูดอย่างเคร่งครัดถ้าคุณต้องการมันเป็นฟังก์ชัน Ajax (ซึ่งส่วนใหญ่คือสิ่งที่ฉันใช้เพื่อ) มันเป็น overkill นอกจากว่าคุณระวังตัวคุณอาจพบว่ามันเป็น "เวทมนต์" มากเกินไป (เช่นการขยายองค์ประกอบ dom ทุกชิ้นที่สัมผัสกับฟังก์ชั่น Prototype JS เพื่อค้นหาองค์ประกอบ) ทำให้ช้าลงในกรณีที่รุนแรง


แค่สงสัยว่ามีอะไรในตัว ดูเหมือนว่าควรจะมี ฉันเกลียดต้นแบบ แต่ฉันไม่ได้ถือได้ว่ากับคุณ :)

เมื่อ JavaScript ได้รับการออกแบบแล้ว Ajax ยังไม่ถูกค้นพบดังนั้นจึงทำการแยกแบบฟอร์มเพื่อรับการสอบถาม (ว่าจะสร้างเองเมื่อส่ง) อาจไม่สมเหตุสมผลนัก วันนี้มันไม่ยาก ... Btw เมื่อเทียบกับ script.aculo.us, ต้นแบบที่ดี :)
Stein G. Strindhaug

10

การสอบถามสามารถช่วยได้

คุณสามารถ

const querystring = require('querystring')

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

3
สำหรับแอปพลิเคชันส่วนหน้าคุณอาจพิจารณาnpmjs.com/package/qs ด้วย
Robert Pankowecki

@ RobertPankowecki ใช่ qs นั้นดีกว่าและมีอยู่แล้วในคลังแสงของฉันไชโย!
ImLeo

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

เบราว์เซอร์ที่เก่ากว่าจะต้องใช้ polyfill


3

ฉันไม่แน่ใจตัวเองทั้งหมดฉันจำได้ว่าเห็น jQuery ทำมันถึงขนาด แต่มันไม่ได้จัดการระเบียนลำดับชั้นเลยให้อยู่คนเดียวในวิธีที่เป็นมิตรกับ PHP

สิ่งหนึ่งที่ฉันรู้แน่ ๆ ก็คือเมื่อสร้าง URL และติดผลิตภัณฑ์ลงใน dom ไม่เพียง แต่ใช้ string-glue ทำมันหรือคุณจะเปิดตัวเองไปที่ตัวแบ่งหน้าเว็บที่มีประโยชน์

ตัวอย่างเช่นซอฟต์แวร์โฆษณาบางรายการจะจัดเรียงสตริงเวอร์ชันจากสิ่งที่เรียกใช้แฟลชของคุณ นี่เป็นเรื่องปกติเมื่อสตริงธรรมดาทั่วไปของ adobes แต่มันไร้เดียงสามากและทำให้เกิดความอับอายสำหรับผู้ที่ติดตั้ง Gnash เนื่องจากสตริงของ gnash'es นั้นมีลิขสิทธิ์ GPL ที่เต็มไปด้วย URL ที่สมบูรณ์ และ <a href> แท็ก การใช้สิ่งนี้ในเครื่องมือสร้างสตริงโฆษณาติดกาวของคุณจะส่งผลให้มีการเปิดหน้าเว็บและมี HTML ที่ไม่สมดุลปรากฏขึ้นใน dom

คุณธรรมของเรื่องราว:

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

ไม่:

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

Google จำเป็นต้องเรียนรู้เคล็ดลับนี้ ฉันพยายามที่จะรายงานปัญหาพวกเขาดูเหมือนจะไม่สนใจ


ถูกต้อง Document.write เป็นเช่นนั้นในปี 1995

2

ในฐานะที่เป็นสไตน์กล่าวว่าคุณสามารถใช้ห้องสมุดจาวาสคริปต์ต้นแบบจาก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, และhashparameters

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.