- 原文地址:Offline-Friendly Forms
- 原文做者:mxbck
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:sunui
- 校對者:yanyixin、Tina92
網絡不佳時網頁表單的表現一般並不理想。若是你試圖在離線狀態下提交表單,那就極可能丟失剛剛填好的數據。下面就看看咱們是如何修復這個問題的。前端
太長,勿點:這裏是本文的 CodePen Demo。react
隨着 Service Workers 的推行,如今開發者們甚至能夠實現離線版的網頁了。靜態資源的緩存相對容易,而像表單這樣須要服務器交互的狀況就很難優化了。即便這樣,提供一些有用的離線回退方案仍是有可能的。android
首先,咱們爲離線友好的表單建立一個新的類。接着咱們保存一些 <form>
元素的屬性而後綁定一個觸發 submit 事件的函數:ios
class OfflineForm {
// 配置實例。
constructor(form) {
this.id = form.id;
this.action = form.action;
this.data = {};
form.addEventListener('submit', e => this.handleSubmit(e));
}
}複製代碼
在 submit 處理函數中,咱們使用 navigator.onLine
屬性內置一個簡單的網絡檢查器。瀏覽器對它的支持很好,並且實現它也不難。git
⚠️ 但它仍是有必定誤報的可能,由於這個屬性只能檢查客戶端是否鏈接到網絡,而不能檢測實際的網絡連通性。另外一方面,一個 false
值意味着「離線」是相對肯定的。所以,比起其餘方式這個判斷方法是最好的。github
若是一個用戶當前處於離線狀態,咱們就暫停表單的提交,把數據存儲在本地。ajax
handleSubmit(e) {
e.preventDefault();
// 解析表單輸入,存儲到對象中
this.getFormData();
if (!navigator.onLine) {
// 用戶離線,在設備中存儲數據
this.storeData();
} else {
// 用戶在線,經過 ajax 發送數據
this.sendData();
}
}複製代碼
存儲數據到用戶設備有幾種不一樣的方式。根據數據的不一樣,若是你不但願本地副本持久存儲在內存中,可使用 sessionStorage
。在咱們的例子中,咱們能夠一塊兒使用 localStorage
。axios
咱們能夠給表單數據附上時間戳,把它賦值給一個新的對象,而且使用 localStorage.setItem
保存。這個方法接受兩個參數:key(表單 id)和 value(數據的 JSON 串)。後端
storeData() {
// 檢測 localStorage 是否可用
if (typeof Storage !== 'undefined') {
const entry = {
time: new Date().getTime(),
data: this.data,
};
// 把數據存儲爲 JSON 串
localStorage.setItem(this.id, JSON.stringify(entry));
return true;
}
return false;
}複製代碼
提示:你能夠在 Chrome 的開發者工具 「Application」 中查看存儲數據。若是不出差錯,你能夠看到內容以下:瀏覽器
通知用戶發生了什麼也是個好主意,這樣他們會知道他們的數據不會丟失。咱們能夠擴展 handleSubmit
函數來顯示某些反饋信息。
多麼周到的表單!
一旦用戶聯網,咱們想檢查一下是否有被存儲的提交。咱們能夠監聽 online
事件來捕獲網絡連接的改變,還有頁面刷新時的 load
事件:
constructor(form){
...
window.addEventListener('online', () => this.checkStorage());
window.addEventListener('load', () => this.checkStorage());
}複製代碼
checkStorage() {
if (typeof Storage !== 'undefined') {
// 檢測咱們是否在 localStorage 之中存儲了數據
const item = localStorage.getItem(this.id);
const entry = item && JSON.parse(item);
if (entry) {
// 捨棄超過一天的提交。 (可選)
const now = new Date().getTime();
const day = 24 * 60 * 60 * 1000;
if (now - day > entry.time) {
localStorage.removeItem(this.id);
return;
}
// 咱們已經驗證了表單數據,嘗試提交它
this.data = entry.data;
this.sendData();
}
}
}複製代碼
一旦咱們成功提交了表單,那最後一步就是移除 localStorage
中的數據,來避免重複提交。假設是一個 ajax 表單,咱們能夠在服務器響應成功的回調裏作這件事。很簡單,這裏咱們可使用 storage 對象的 removeItem()
方法。
sendData() {
// 向服務器發送 ajax 請求
axios.post(this.action, this.data)
.then((response) => {
if (response.status === 200) {
// 成功時移除存儲的數據
localStorage.removeItem(this.id);
}
})
.catch((error) => {
console.warn(error);
});
}複製代碼
若是你不想使用 ajax 提交,另外一個方案是將存儲的數據回填到表單,而後調用 form.submit()
或讓用戶本身點擊提交按鈕。
☝️ 注意:簡單起見,我在這個案例中省略了一些其餘部分,好比表單驗證和安全 token 驗證等,這些東西在真正的生產環境是必不可少的。這裏的另外一個問題是處理敏感數據,就是說你不能在本地存儲一些密碼或者信用卡數據等私密信息。
若是你感興趣,請查閱 CodePen 上的所有示例。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。