接收表單數據:serialize()函數解析

一、form-serialize作用與引入

作用:
form-serialize可以快速收集表單數據,按照使用者意愿轉化為對象或字符串輸出,以便于提交至服務器。
引入:
form-serialize不是瀏覽器自帶的JS方法,而是第三方工具庫。可以直接通過scrip標簽引入:

<script src="https://cdn.jsdelivr.net/npm/form-serialize@0.7.2/form-serialize.min.js"></script>

或者到npm網站搜索form-serialize(),將代碼文件保存到本地引入,也可以在終端安裝后直接使用require獲取:

npm install form-serialize
import serialize from 'form-serialize';const data = serialize(form, { hash: true, empty: true });

二、輸出

serialize的使用方法為:

const form=document.querySelector('form')
/*
假設表單內容為:
<form action=""><input type="text" name="username" id="" value="user"><input type="text" name="age" id="" value="18"><input type="text" name="infor" id="" value="">
</form>
*/
//1.轉化為query string參數
const data=serialize(form)
//2.轉化為沒有空內容的對象
const dataobj=serialize(form,hash:true)
//3.轉化為有空內容的對象
const dataobjWithEempty=serialize(form,{hash:true,empty:true})
  • 方法1傳出為:www.example.com?username=user&age=18
    這個形式的字符串可以直接作為AJAX請求的body或URL的query string
  • 方法2傳出為:
dataobj={username:'user',age:18
}
  • 方法3傳出為:
dataobj={username:'user',age:18,infor:''
}

發現區別了嗎?方法一傳出query string字符串,方法二傳出不含空白字符串的表單數據對象,方法三會將收集到的所有信息傳出為對象。其中:

  • hash在代表哈希表,是一種鍵值對應的對象,所以{hash:true}就代表傳出對象。
  • empty:true則代表傳出對象中包含空白字符串,接下來我們觀察底層代碼如何實現。

從npm下載的完整js代碼放在文末

三、解析

serialize函數定義:

function serialize(form, options) {if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}var result = (options.hash) ? {} : '';var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);var elements = form && form.elements ? form.elements : [];//Object store each radio and set if it's empty or notvar radio_store = Object.create(null);for (var i=0 ; i<elements.length ; ++i) {var element = elements[i];// ingore disabled fieldsif ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}var key = element.name;var val = element.value;// we can't just use element.value for checkboxes cause some browsers lie to us// they say "on" for value when the box isn't checkedif ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}// If we want empty elementsif (options.empty) {// for checkboxif (element.type === 'checkbox' && !element.checked) {val = '';}// for radioif (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radioif (val == undefined && element.type == 'radio') {continue;}}else {// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}// multi select boxesif (element.type === 'select-multiple') {val = [];var selectOptions = element.options;var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];var allowedEmpty = options.empty && !option.value;var hasValue = (option.value || allowedEmpty);if (option.selected && hasValue) {isSelectedOptions = true;// If using a hash serializer be sure to add the// correct notation for an array in the multi-select// context. Here the name attribute on the select element// might be missing the trailing bracket pair. Both names// "foo" and "foo[]" should be arrays.if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}result = serializer(result, key, val);}// Check for all empty radio buttons and serialize them with key=""if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}return result;
}

我們可以發現,要求傳入參數為:(form,options),form為我們獲取的表單對象,options可以省略。
首先,程序查詢傳入參數:

    if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}

如果options不是對象,就使用!!強行將options轉化為bool值,存儲到hash屬性中,并將這對鍵值轉化為對象。

這允許我們在使用serialize轉化對象時簡寫:const dataobj=serialize(form,true)

完成了簡寫判斷,進行options為對象時的判斷:

	//result為傳出參數//hash為:真-result初始化為對象;假-初始化為字符串var result = (options.hash) ? {} : '';//options.serializer存在,直接使用,若不存在://hash為true,調用hash_serializer//hash為false,調用str_serializevar serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);

其中:

  • hash_serializer:自定義函數,將表單數據序列化為 JavaScript 對象。
  • str_serialize:自定義函數,將表單數據序列化為 URL 編碼的字符串。

接下來,接收radio類型單選按鈕數據,創建空對象:

	//將表單格式化為數組,進行遍歷var elements = form && form.elements ? form.elements : [];//創建空對象var radio_store = Object.create(null);

之后進入遍歷elments的for循環

在下面這段代碼中:

  • 過濾掉不需要序列化的字段:
  • 禁用的字段(除非 options.disabled 為 true)。
  • 沒有 name 屬性的字段。
  • 不屬于“成功控件(表單要收集的數據)”的字段。
        if ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}

在下面這段代碼中:

  • 設置表單的鍵與值
  • 檢查復選框與單選框是否被選中,若沒有,標記為undefined,表示不該被記錄。
		var key = element.name;var val = element.value;if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}

獲取屬性:

// If we want empty elements-如果options.empty為true,即我們需要空白字符串值
if (options.empty) {// for checkbox-獲取復選框值if (element.type === 'checkbox' && !element.checked) {val = '';}// for radio-獲取單選框值if (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radio//如果控件無有效值(未被選擇)且為單選框,直接進行下次迭代if (val == undefined && element.type == 'radio') {continue;}}else {//不需要空字符串的情況,沒有值直接跳過// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}

接下來進行遍歷中的多選下拉選項獲取(單選下拉可以直接通過下拉對象的value屬性獲取)

if (element.type === 'select-multiple') {//初始化值數組val = [];//獲取選項數組,用于遍歷var selectOptions = element.options;//每次迭代初始化未被選擇bool類型var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];//該選項是否被允許空值var allowedEmpty = options.empty && !option.value;//當前選項是否有有效值:有真值或被允許空值var hasValue = (option.value || allowedEmpty);//是否被選擇,是否有有效值if (option.selected && hasValue) {//給bool值賦值:被選中isSelectedOptions = true;// 處理格式/*如果用戶配置了 options.hash 為 true,表示需要將結果序列化為對象格式。key.slice(key.length - 2) !== '[]':檢查當前選項的 name 屬性是否以 [] 結尾。如果沒有以 [] 結尾,則在鍵名后面追加 [],以確保多選下拉框的值被正確處理為數組。遞歸調用 serializer:調用序列化函數(hash_serializer 或 str_serialize),將當前選項的鍵值對添加到結果中:如果是對象序列化(hash_serializer),會將值存儲為數組。如果是字符串序列化(str_serialize),會將值編碼為 URL 查詢字符串格式。*/if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}

這是獲取復選下拉的部分,接下來:

遞歸調用,將當前表單鍵值對序列化添加到結果中,以便于處理正確的嵌套邏輯。

result = serializer(result, key, val);

檢查所有的值都不為空/未定義

	//如果允許空字符串if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}//若未允許空字符串,在前面值為空的對象會直接跳過進入下次迭代

返回結果:

return result;

四、form-serialize.js文件完整代碼

// get successful control from form and assemble into object
// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2// types which indicate a submit action and are not successful controls
// these will be ignored
var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;// node names which could be successful controls
var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;// Matches bracket notation.
var brackets = /(\[[^\[\]]*\])/g;// serializes form fields
// @param form MUST be an HTMLForm element
// @param options is an optional argument to configure the serialization. Default output
// with no options specified is a url encoded string
//    - hash: [true | false] Configure the output type. If true, the output will
//    be a js object.
//    - serializer: [function] Optional serializer function to override the default one.
//    The function takes 3 arguments (result, key, value) and should return new result
//    hash and url encoded str serializers are provided with this module
//    - disabled: [true | false]. If true serialize disabled fields.
//    - empty: [true | false]. If true serialize empty fields
function serialize(form, options) {if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}//真:初始化為對象,假:初始化為字符串var result = (options.hash) ? {} : '';var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);var elements = form && form.elements ? form.elements : [];//Object store each radio and set if it's empty or notvar radio_store = Object.create(null);for (var i=0 ; i<elements.length ; ++i) {var element = elements[i];// ingore disabled fieldsif ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}var key = element.name;var val = element.value;// we can't just use element.value for checkboxes cause some browsers lie to us// they say "on" for value when the box isn't checkedif ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}// If we want empty elementsif (options.empty) {// for checkboxif (element.type === 'checkbox' && !element.checked) {val = '';}// for radioif (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radioif (val == undefined && element.type == 'radio') {continue;}}else {// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}// multi select boxesif (element.type === 'select-multiple') {val = [];var selectOptions = element.options;var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];var allowedEmpty = options.empty && !option.value;var hasValue = (option.value || allowedEmpty);if (option.selected && hasValue) {isSelectedOptions = true;// If using a hash serializer be sure to add the// correct notation for an array in the multi-select// context. Here the name attribute on the select element// might be missing the trailing bracket pair. Both names// "foo" and "foo[]" should be arrays.if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}result = serializer(result, key, val);}// Check for all empty radio buttons and serialize them with key=""if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}return result;
}function parse_keys(string) {var keys = [];var prefix = /^([^\[\]]*)/;var children = new RegExp(brackets);var match = prefix.exec(string);if (match[1]) {keys.push(match[1]);}while ((match = children.exec(string)) !== null) {keys.push(match[1]);}return keys;
}function hash_assign(result, keys, value) {if (keys.length === 0) {result = value;return result;}var key = keys.shift();var between = key.match(/^\[(.+?)\]$/);if (key === '[]') {result = result || [];if (Array.isArray(result)) {result.push(hash_assign(null, keys, value));}else {// This might be the result of bad name attributes like "[][foo]",// in this case the original `result` object will already be// assigned to an object literal. Rather than coerce the object to// an array, or cause an exception the attribute "_values" is// assigned as an array.result._values = result._values || [];result._values.push(hash_assign(null, keys, value));}return result;}// Key is an attribute name and can be assigned directly.if (!between) {result[key] = hash_assign(result[key], keys, value);}else {var string = between[1];// +var converts the variable into a number// better than parseInt because it doesn't truncate away trailing// letters and actually fails if whole thing is not a numbervar index = +string;// If the characters between the brackets is not a number it is an// attribute name and can be assigned directly.if (isNaN(index)) {result = result || {};result[string] = hash_assign(result[string], keys, value);}else {result = result || [];result[index] = hash_assign(result[index], keys, value);}}return result;
}// Object/hash encoding serializer.
function hash_serializer(result, key, value) {var matches = key.match(brackets);// Has brackets? Use the recursive assignment function to walk the keys,// construct any missing objects in the result tree and make the assignment// at the end of the chain.if (matches) {var keys = parse_keys(key);hash_assign(result, keys, value);}else {// Non bracket notation can make assignments directly.var existing = result[key];// If the value has been assigned already (for instance when a radio and// a checkbox have the same name attribute) convert the previous value// into an array before pushing into it.//// NOTE: If this requirement were removed all hash creation and// assignment could go through `hash_assign`.if (existing) {if (!Array.isArray(existing)) {result[key] = [ existing ];}result[key].push(value);}else {result[key] = value;}}return result;
}// urlform encoding serializer
function str_serialize(result, key, value) {// encode newlines as \r\n cause the html spec says sovalue = value.replace(/(\r)?\n/g, '\r\n');value = encodeURIComponent(value);// spaces should be '+' rather than '%20'.value = value.replace(/%20/g, '+');return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
}module.exports = serialize;

五、原庫獲取地址

form-serialize - npm

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89530.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89530.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89530.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vc配置使用預編譯

預編譯原理 stdafx.h中加入系統文件&#xff0c;減少cpp中對這些文件的解析&#xff0c;提高速度 stdafx.h 會把編譯的文件生成pch&#xff0c;后續解析頭文件直接調用pch里面的數據 配置 新建stdafx.h和stdafx.cpp文件 配置stdafx.cpp文件為/Yc 創建預編譯文件整個項目設置/Yc…

反射機制的登錄系統

一、實體層&#xff08;po層&#xff09; //UserInfo package com.hugeyurt.po;import java.sql.ResultSet; import java.sql.SQLException;public class UserInfo {private String userID;private String name;private int count;private Long errorTime;private String pwd;p…

裝飾器模式及優化

裝飾器模式&#xff08;Decorator Pattern&#xff09;是一種結構型設計模式&#xff0c;它允許向一個現有的對象添加新的功能&#xff0c;同時又不改變其結構。這種模式創建了一個裝飾器類&#xff0c;用來包裝原有的類&#xff0c;并在保持類方法簽名完整性的前提下&#xff…

共指消解技術全解析:從語言學規則到深度學習(附論文精讀)

精讀威斯康星大學綜述《Coreference Resolution: A Survey》&#xff0c;揭秘NLP中"實體鏈接"的核心技術一、什么是共指消解&#xff1f;為什么它是NLP的基石&#xff1f;共指消解(Coreference Resolution) 旨在識別文本中指向同一實體的不同表述。例如&#xff1a;t…

git配置git commit -m “fix 11,22: 修改bugid為11,22“

文章目錄前言一、報錯提示二、實現1.commitlint.config.js規范配置2. **修改正則表達式**&#xff1a;3. **移除 scope-case 規則**&#xff1a;4. **增強自定義規則邏輯**&#xff1a;測試結果&#xff1a;正則表達式詳解&#xff1a;前言 提示&#xff1a;正常的配置git規范…

nastools繼任者?極空間部署影視自動化訂閱系統『MediaMaster』

nastools繼任者&#xff1f;極空間部署影視自動化訂閱系統『MediaMaster』 哈嘍小伙伴們好&#xff0c;我是Stark-C~ 對于我們NAS玩家來說&#xff0c;觀影總是大家繞不開的一個執念&#xff0c;并且為觀影的折騰大家也都是樂此不疲~ 曾經有一個非常絕絕子的觀影神器擺在我們…

題解:CF1690G Count the Trains

思路&#xff1a; 首先我們可以理清一下各種情況&#xff1a;1&#xff09;m可能為02&#xff09;一次操作時&#xff0c;只需要考慮每節火車的車頭。3&#xff09;當一節火車的速度降低時&#xff0c;只會影響它及它后面的車廂當m0時&#xff0c;我們可以記錄上一節車頭的速度…

CCF編程能力等級認證GESP—C++3級—20250628

CCF編程能力等級認證GESP—C3級—20250628單選題&#xff08;每題 2 分&#xff0c;共 30 分&#xff09;判斷題&#xff08;每題 2 分&#xff0c;共 20 分&#xff09;編程題 (每題 25 分&#xff0c;共 50 分)奇偶校驗分糖果單選題&#xff08;每題 2 分&#xff0c;共 30 分…

2G和3G網絡關閉/退網狀態(截止2025年7月)

從能打語音電話的2G&#xff0c;到能發彩信、聊QQ的3G&#xff0c;這兩項陪伴了我們數十年的通信技術&#xff0c;正在悄然退出歷史舞臺。近日&#xff0c;全球移動供應商協會&#xff08;GSA&#xff09;發布的《2025年7月2G和3G網絡關閉報告》顯示&#xff0c;全球已有超百個…

Day06_C語言網絡編程20250718mobus重點

01.思維導圖1 什么是 modbus他是一個在工控領域非常好用的通信寫 modbus協議本質上是一個 基于 tcp 協議二次封裝的一個協議 什么叫做基于tcp二次封裝的協議&#xff1a;我們自己寫的pack_t(無論靜態還是動態)&#xff0c;都是屬于二次封裝的協議modbus協議是一種 “主從問答式…

比亞迪古德伍德亮相:從技術突破到文化對話

近日&#xff0c;比亞迪攜騰勢Z9GT、方程豹豹5、騰勢D9亮相英國古德伍德速度節——全球最具聲望的汽車文化盛典。方程豹豹5搭載全球首個 DMO電驅越野平臺&#xff0c;在爬山賽道上展現出媲美性能跑車的動力響應與精準控制&#xff0c;徹底打破“越野必靠大排量燃油機”的西方傳…

UniApp TabBar 用戶頭像方案:繞過原生限制的實踐

需求場景&#xff1a; 在 UniApp 項目中&#xff0c;需要將 TabBar 首頁項 (index) 的圖標替換為當前用戶的網絡圖片&#xff0c;并實現&#xff1a; 放大且圓形顯示。點擊該圖標時&#xff0c;頁面滾動回頂部。切換到其他分類時&#xff0c;首頁 Tab 項恢復為普通首頁圖標。 嘗…

如何閱讀Spring源碼

如何閱讀Spring源碼 簡介 最近有許多人問我如何閱讀Spring源碼&#xff0c;那我便在這給出閱讀源碼的方法&#xff0c;能夠保證本地能夠讓源碼能夠運行起來。 Spring 源碼環境本地編譯 Gradle下載地址 通過網盤分享的文件&#xff1a;gradle-6.4.1-all.zip 鏈接: https://pan.b…

Excel導出實戰:從入門到精通 - 構建專業級數據報表的完整指南

文章目錄Excel導出實戰&#xff1a;從入門到精通 - 構建專業級數據報表的完整指南引言&#xff1a;ExcelJSFileSaver如何映射到Excel操作一、ExcelJS核心架構解析 - 從文件結構理解1. 工作簿(Workbook)模型 - 相當于整個Excel文件2. 工作表(Worksheet)配置 - 相當于單個工作表設…

PyTorch圖像預處理全解析(transforms)

1. 引言在深度學習計算機視覺任務中&#xff0c;數據預處理和數據增強是模型訓練的關鍵步驟&#xff0c;直接影響模型的泛化能力和最終性能表現。PyTorch 提供的 torchvision.transforms 模塊&#xff0c;封裝了豐富的圖像變換方法&#xff0c;能夠高效地完成圖像標準化、裁剪、…

slam中的eskf觀測矩陣推導

在之前的《slam中的eskf推導》一文中&#xff0c;沒有寫觀測矩陣 H 矩陣的過程&#xff0c;現在補上這部分。前置列舉幾個等下推導需要用到的一些點&#xff1a;平面特征點構造觀測矩陣例如在 fastlio 中&#xff0c;是利用平面特征點到擬合平面的距離來構造觀測方程&#xff0…

Python_2

邏輯判斷 首先得首先&#xff0c;我們想判斷一個邏輯的正確與否&#xff0c;一定是需要一個能夠表現出邏輯的詞 如果我只說一個1 2&#xff0c;那么大家都不知道我在說什么但是如果我說1<2,那么大家就能判斷這個語句的正確與否了 下面是幾個常用的邏輯詞 < 小于>大于&…

Liunx-Lvs配置項目練習

1.實驗環境配置Lvs調度器有兩塊網卡 一塊僅主機和一塊nat網卡&#xff0c;客戶端nat模式&#xff0c;兩臺服務器為僅主機模式2.集群和分布式簡介集群與分布式系統簡介集群 (Cluster)集群是指將多臺計算機(通常為同構的)通過高速網絡連接起來&#xff0c;作為一個整體對外提供服…

T5(Text-to-Text Transfer Transformer) 模型

下面是對 T5&#xff08;Text-to-Text Transfer Transformer&#xff09; 模型的詳細介紹&#xff0c;包括其原理、架構、訓練方式、優勢與局限&#xff0c;以及與其他模型&#xff08;如 BERT、GPT&#xff09;的對比。一、T5 是什么&#xff1f;T5&#xff08;Text-to-Text T…

PostgreSQL技術大講堂 - 第97講:PG數據庫編碼和區域(locale)答疑解惑

PostgreSQL從入門到精通系列課程&#xff0c;近100節PG技術講解&#xff0c;讓你從小白一步步成長為獨當一面的PG專業人員&#xff0c;點擊這里查看章節內容。 PostgreSQL從入門到精通課程&#xff0c;持續更新&#xff0c;歡迎加入。第97講&#xff1a;PostgreSQL 數據庫編碼…