這個表單打死我也不填!
theme: v-green highlight: atom-one-dark
本文為掘金社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!
前言
表單在應用內隨處可見,註冊、登入、完善個人資料、發表內容……在 B 端應用中,表單操作更是員工日常工作中使用最多的功能。好的表單體驗能夠讓使用者更加輕鬆地完成資訊錄入,從而讓我們獲知更多使用者的資訊、在應用內產生更多內容或者讓員工的工作更為輕鬆。糟糕的表單,則會讓使用者感到絕望,有一種打死也不想填的感覺!那麼,對於開發而言,如何提高表單操作的使用者體驗?本篇我們就來講講常見的提高表單使用者體驗的方式,推薦在封裝表單元件的時候將這些因素考慮進去,形成公司內統一的規範,保持體驗的一致性。
錯誤提示
表單輸入不可避免會出錯,及時、準確地給出錯誤提示能夠讓使用者快速更正錯誤,提高表單錄入的效率。錯誤提示有以下三種方式:
- 內聯提示:當輸入完成後,立即校驗表單內容並給出錯誤提示;
- 提交時客戶端提示:輸入完成後,點選提交按鈕時對整個表單進行錯誤校驗和提示;
- 提交後服務端校驗:提交到後端後,有服務端應用對錶單進行校驗。
對於輸入表單內容較少的錯誤提示,推薦採用內聯的方式實現。內聯方式的錯誤提示就是將錯誤資訊直接顯示在表單附近(通常是下方),這樣使用者更容易察覺。我們來看看在 Flutter 中如何實現內聯的錯誤提示。
Flutter 的TextField
元件有一個 decoration
屬性,型別為InputDecoration
。通過 InputDecoration
類的errorText
和errorStyle
可以構建一個 Text
元件,當 errorText
不為空時就會預設在 TextField
下方顯示錯誤指示,從而提示使用者輸入有誤,示例程式碼和執行結果如下。需要注意的是,錯誤提示資訊應該準確,避免泛泛的錯誤提示。我曾經遇到過的反面例子就是產品沒有明確錯誤提示(很多產品因為見過不少標準的錯誤提示,就預設開發也知道如何提示錯誤,所以文件並不會給出錯誤提示文案),然後開發直接粗暴地顯示一個“輸入有誤”的標準提示。
dart
TextField(
autofocus: true,
decoration: InputDecoration(
label: const Text('郵箱'),
hintText: '請輸入電子郵箱地址',
errorText: _errorText,
errorStyle: TextStyle(color: Colors.red[400], fontSize: 14.0),
),
onEditingComplete: () {
if (!FormUtils.isValidEmail(_email)) {
setState(() {
_errorText = '請輸入正確的郵箱地址';
});
} else {
setState(() {
_errorText = null;
});
}
},
onChanged: (text) {
_email = text;
},
)
對於表單錄入內容較多的情況來說,推薦使用提交時進行錯誤校驗和提示。因為表單內容較多時,通常使用者更希望專注輸入內容,如果經常給出錯誤提示會轉移使用者注意力,打斷使用者填寫表單的思路。
標籤
表單的標籤有三種,頂部標籤、左側標籤和浮動標籤,當然簡潔的設計有時候會使用圖示替代標籤文字。研究表明,頂部標籤的方式填寫表單的效率更高,因為一路向下填寫即可,視線不需要實現 Z 字形路線移動,但是頂部標籤相對來說比較佔空間,在移動端不太多見。大多數國外的應用頂部標籤居多,例如下面是亞馬遜的登入介面。 gmail 則別出新裁地在預設的時候省去了標籤,一旦聚焦標籤顯示在輸入框的上邊框,可以說是將效率和空間做了充分的利用(這種效果在 Flutter 中預設就有,只要TextField 制定了邊框,就會在聚焦後將標籤顯示在邊框上)。
在 Flutter 中,就如同我們上面的例子那樣,預設標籤是不可見的,聚焦後才會以小字的形式顯示上面的標籤。我們來看看 Flutter 文字輸入框的標籤具體如何設定。Flutter 為設定標籤樣式和互動提供了3個屬性:
labelStyle
:TextStyle
物件,用於設定預設的標籤樣式。floatingLabelStyle
:設定浮動狀態(即標籤在輸入框上方)時的標籤狀態,這個屬性可以是TextStyle
物件也可以是MaterialStateTextStyle
物件,如果是MaterialStateTextStyle
物件的話,就可以設定不同狀態下的標籤樣式,比如錯誤、聚焦和游標移入等。floatingLabelBehavior
:設定浮動標籤的互動行為,預設是auto
,即聚焦的時候才顯示,也可以設定為never
不顯示標籤,或者設定為always
一直顯示標籤。
下面是對應的程式碼,我們來看看不同形式的區別:
dart
Column(
children: [
TextField(
autofocus: true,
decoration: InputDecoration(
label: const Text('郵箱'),
hintText: '請輸入電子郵箱地址',
floatingLabelStyle: MaterialStateTextStyle.resolveWith(
(Set<MaterialState> states) {
final Color color;
if (states.contains(MaterialState.error)) {
color = Colors.red[400]!;
} else if (states.contains(MaterialState.focused)) {
color = Colors.blue[400]!;
} else {
color = Colors.black54;
}
return TextStyle(
color: color,
);
}),
floatingLabelBehavior: FloatingLabelBehavior.always,
errorText: _errorText,
errorStyle: TextStyle(color: Colors.red[400], fontSize: 14.0),
),
onEditingComplete: () {
if (!FormUtils.isValidEmail(_email)) {
setState(() {
_errorText = '請輸入正確的郵箱地址';
});
} else {
setState(() {
_errorText = null;
});
}
},
onChanged: (text) {
_email = text;
},
),
TextField(
decoration: InputDecoration(
label: const Text('密碼'),
hintText: '請輸入密碼',
floatingLabelBehavior: FloatingLabelBehavior.auto,
),
obscureText: true,
),
TextField(
decoration: InputDecoration(
label: const Text('確認密碼'),
hintText: '請再次輸入密碼',
floatingLabelBehavior: FloatingLabelBehavior.never,
),
obscureText: true,
),
],
),
- 第一個表單郵箱我們使用了固定顯示標籤的形式,同時通過
floatingLabelStyle
設定了不同狀態的標籤顏色; - 第二個表單密碼我們使用了
auto
模式,可以看到標籤一開始是在表單行內的,聚焦後標籤移到了輸入框上方,而輸入框會展示佔位文字; - 第三個確認密碼我們使用了
never
模式,標籤一開始是在表單行內的,聚焦後標籤移到了輸入框上方,而輸入框會展示佔位文字,但標籤會消失不見。
從體驗上來說,第一種和第二種會更好些,不過在國內大部分是直接將標籤省略或者使用左側標籤。下面是阿里雲的註冊介面,沒有標籤的表單適用於表單項較少的場景。
對於 Flutter 的 TextField
,如果要使用左側標籤,則需要自定義實現(可以參考之前的文章:)。這裡需要注意,雖然 TextField
提供了一個 prefix
可以自定義前置元件,但是這個元件只會在文字框聚焦的時候才顯示。
鍵盤
鍵盤處理在手機端非常常見了,建議根據輸入型別來設定鍵盤型別,常見的鍵盤型別和用途如下:
TextInputType.number
:輸入數字,帶小數點;TextInputType.phone
:輸入數字,*和#字元,適合撥打電話或輸入號碼;TextInputType.email
:輸入電子郵箱地址;TextInputType.url
:適合輸入連結地址,會預設顯示/和.字元;TextInputType.multiline
:適合多行輸入,帶有回車符,回車後自動換行;
需要注意的是,安卓和 iOS 的鍵盤會有些區別,具體可以看看 TextInputType
的各個列舉值的說明。
表單項過多
當要錄入的表單項很多的時候,如果表單沒有條理性,會讓使用者望而生畏,忍受力強的使用者發發鬧騷,無法忍受的使用者直接放棄。比如下面這樣的登錄檔單,看到就會絕望,打死我也不會填的。 怎麼處理表單項過多?推薦的做法有三種:
- 表單分組:比如將必填的表單分為一組,其他選填的表單分為一組;這種在 PC 端會更適用。
- 分步驟填寫:還是表單分組,但是分多個步驟,每頁展示的表單數量少,不會讓使用者一下子感覺要填很多東西。而且,從心理學上來說,前面填了一部分會讓使用者積累沉沒成本,後面的表單會更願意填。同時,對於非必填的分組提供跳過選項。
- 利用時間差:也就是一開始的時候讓使用者只填很少的資訊,然後在之後的使用過程中逐步引導使用者完善其他資料。比如在領英里,每次就會讓我們填寫一點點資訊,最終將個人資訊收集完整。
表單校驗
前面錯誤提示的時候,已經講過一些校驗的內容了。這裡要說的是,我們開發一定要養成對錶單進行校驗的習慣。本人就遇到過這樣的情況,產品沒有特別說明校驗規則,然後前後端都不校驗,結果錄入的資料導致各種各樣的 bug。這種寫 bug 的行為會極大降低我們程式設計師的段位!對於校驗,建議是在內部形成統一的預設規則,比如下面幾點:
- 文字輸入的最大輸入長度限制;
- 數值的最大輸入範圍;
- 小數預設保留的位數;
- 常用型別資料的校驗規則統一,例如姓名、郵箱、手機號、身份證號、經緯度、日期、企業統一社會信用程式碼,密碼強度、金額等。避免前後端校驗規則不一致。
至於什麼時候校驗,建議是按表單數量來定,表單數量少可以在輸入完成後進行校驗;表單數量多推薦是在完成輸入後整體校驗。同時,前端務必保證提交給後端資料的基本合法性(除了需要後端通過業務邏輯校驗的除外,例如唯一性檢查,是否存在檢查等)。
總結
如果評估一個前端開發做事情的細緻程度,通常會通過他寫的表單業務來評估。基本上,測試一遍表單的輸入互動、錯誤驗證就能夠判斷出來。一個好的前端,即便是產品不說,也會按照規範將互動和基本的校驗做好。同時,保持與產品的溝通也很重要,如果對錶單的校驗規則有疑惑,那一定是需要二次確認的。雖然不確認鍋可以甩給產品,但是 bug 卻是留在自己頭上的。
- 屌炸天!國外同行這樣用Chat GPT提高Flutter開發的效率!
- Flutter 增強版的頁面懸浮按鈕(FloatingActionButton)
- 介紹一個令強迫症討厭的小紅點元件
- 我用了幾行程式碼就搞定了介面變灰效果
- 不就是一個空白頁,有必要那麼講究嗎?
- 花裡胡哨的文字特效,你學會了嗎?
- 這一篇讓你搞定 Flutter 的資料表格
- 用 Flutter 輕鬆做個紅包介面
- 沉浸式彈層越來越多,開發該怎麼做好彈層體驗?
- 列表的載入過程很重要的!
- 這個表單打死我也不填!
- 例項講述開發中的圖片使用者體驗要點
- C 位出道按鈕的自我獨白
- Flutter 繪製3D效果動畫
- 封裝一個有趣的 Loading 元件
- 普通的載入千篇一律,有趣的 loading 萬里挑一
- 由點匯聚成字的動效炫極了
- 給滅霸點顏色看看
- 來看光影流動之美
- Flutter 實現背景圖片毛玻璃效果