下拉選單第一項顯示「請選擇」,使用者沒有換選項卻仍能送出,先看那一項的value。required判斷的是選擇值,不知道哪段文字只是提示。如果「請選擇」的value是choose,瀏覽器會把它當成非空值;要讓普通單選select的提示選項代表未選擇,應給它空字串value。
這類問題常見於聯絡表單的需求類型、預約項目或商品選項。提示文字讓人以為還沒選,但提交資料已經帶了一個值,前後端就容易出現不同判斷。本文比較三種選擇狀態,再把原生驗證與提交資料的用途分開。
先建立帶空值提示的普通單選
<form id="request">
<label for="plan">需求</label>
<select id="plan" name="plan" required>
<option value="">請選擇</option>
<option value="site">建站</option>
</select>
<button type="submit">送出</button>
</form>
這裡select沒有multiple,顯示方式也是一般單選。第一個option直接放在select下,value明確設成空字串。保留提示選項時,原生驗證會認為缺值;選到建站後,提交值則是site,不是畫面上的「建站」。
提示文字和資料值應分清。文字供訪客讀,value供程式判斷;可以修改文字讓它更自然,但不要隨意改掉後端需要的代碼。若建站對應site、維護對應maintenance,就讓前後端都使用同一套約定,而不是從顯示文字猜用途。
不寫value,提示文字可能就成了值
option沒有value屬性時,瀏覽器會從選項文字取得值。因此<option>請選擇</option>看起來像提示,資料卻不是空的。只替select加required仍不能達到「必須換一個正式項目」的效果。
同樣地,<option value="choose">請選擇</option>也有非空值。choose這個字對瀏覽器沒有特殊含義,不會自動被當成未完成。使用disabled或灰色樣式也不是一套通用驗證規則,應先把提示選項的資料值設對。
如果你使用多選、較大的size顯示列表,或把提示放進optgroup,原生select的提示選項規則就不能直接照普通單選理解。先確認你的元素結構,再依所需操作設計。本文的空提示例子限定為一般單選,不宣稱所有選單形式都能用同一個第一項解決。
用瀏覽器看valueMissing
開啟這個獨立頁面後,可以在開發者工具查看以下幾個值。checkValidity檢查元素是否符合當前原生限制;valueMissing則讓你知道是否是required缺值,而不是其他限制。
const select = document.querySelector('#plan');
console.log(select.value);
console.log(select.validity.valueMissing);
console.log(select.checkValidity());
在Chromium154實際比較,空提示的value是空字串,valueMissing為true、checkValidity為false。把提示value改成choose後,仍顯示同樣的「請選擇」,但valueMissing變為false、checkValidity變為true。選到site時則得到site,驗證同樣通過。
這個結果說明,畫面上的提示字樣本身不控制有效性。若功能要求使用者只能從你提供的正式代碼中選擇,後端還要驗證代碼是否在允許清單;不能因為瀏覽器說有效,就相信任何送來的非空字串。
FormData會整理資料,但不代替驗證
const form = document.querySelector('#request');
const data = new FormData(form);
console.log([...data.entries()]);
保留可提交的空提示時,這段程式仍能產生plan對應空字串的資料。FormData建立資料物件,不會因為select無效就自動拋出「表單沒有填好」的錯誤。若你用fetch自行送出,應在適當的提交流程確認有效性,再決定是否建立與送出資料。
使用原生submit按鈕時,正常的交互驗證會檢查表單限制;但novalidate等設定或不同提交方式,可能略過這段。排查時要看真正的送出路徑,不要只用new FormData得到幾列結果,就判定表單驗證已經完成。
disabled提示不是唯一解法
有些版型會把提示option設為disabled,避免使用者選到正式項目後又回到提示。這可以是介面選擇,但disabled選項與一般選項在提交資料上也有差別,所以後端仍要接受缺席或空值並給出清楚錯誤。
如果你的需求允許使用者取消選擇,禁止回到提示可能反而不方便。先決定訪客應否能清除,再選擇是否停用提示。不要把「提示不能點」當成萬用做法,尤其在編輯舊資料、重設表單或動態更新選項時,更容易出現沒有合適選擇的狀態。
selected也與disabled不同。selected描述預設選擇,disabled描述能否選取或提交;它們都不能代替空值與required的設計。建立表單時可以讓空提示為預設,再測使用者選正式值、清除與重設後的結果。
動態選項更新後,重新看實際值
若縣市、方案或分類選單由JavaScript重新產生,先前選到的value可能不再存在。更新選項後,應重新確認select.value與驗證狀態,讓畫面文字、提交資料及提示一致。不能只保留前端變數裡的舊代碼,就以為欄位仍維持同一個有效選擇。
使用者看不到的錯誤也要給出口。如果選項載入失敗,直接留一個required空選單而沒有說明,訪客會不知道如何繼續。可以提供重新載入或其他聯絡方式,但不要硬塞一個非空預設值來讓驗證通過,否則收到的需求資料可能是你替訪客猜的。
上線前用三份資料核對
如果表單使用JavaScript處理submit事件,應確認程式在錯誤時保留使用者的其他輸入,而不是整張表單重設。讓訪客重新選需求即可,不必要求他再輸入姓名和訊息。錯誤提示也應靠近選單,說明要選正式項目,不能只在頁面頂部顯示一個沒有對應欄位的「提交失敗」。
新增選項時,維護者應同時更新後端允許清單。前端出現新代碼但後端不認得,訪客就會遇到「選得出卻送不了」;後端仍接受已下架代碼,則可能收到不可處理的需求。這是資料約定的維護工作,不能靠required解決。
若你暫時沒有可選項目,應向訪客說明狀態,避免顯示一個永遠無法通過的必填欄位。比如服務尚未開放時,提供可用的查詢或聯絡方式;資料載入中則顯示相應提示。這些訊息應按實際功能設計,不要用假的預設方案讓表單勉強送出。
最後也看回填舊資料的情況。如果後端存的是site,選單應正確選回site;若舊代碼已移除,應清楚呈現需要重新選擇,而不是偷偷替換成第一個正式項目。保持訪客看到的選擇與真正提交的值一致,才不會讓一個小欄位影響整份需求內容。
至少測提示未改、正式site、任意不支援代碼三種輸入。第一種應要求補選,第二種應正常處理,第三種應由後端拒絕。再核對表單重設後回到哪個選項,以及錯誤提示能否讓人知道要修改哪一欄。
這些測試不需要操作真實客戶訂單。用獨立測試頁與合成需求即可先確認原生行為,再到你自己的測試站核對實際提交路徑。修好空提示是一個欄位的驗證改善,後端的權限、價格或可用方案仍要按各自規則處理。

評論0