防止长表单数据丢失方案,缓存表单填写内容,放置卡退或误操作返回。
一、存储方案(多端兼容)
1. 使用 UniApp 的数据存储 API
// utils/storage.js
export class FormDraftManager {constructor(formKey = 'formDraft') {this.formKey = formKey;}// 保存草稿saveDraft(formData) {const draft = {data: formData,timestamp: Date.now(),formVersion: '1.0'};try {uni.setStorageSync(this.formKey, draft);return true;} catch (e) {console.error('保存草稿失败:', e);return false;}}// 获取草稿getDraft() {try {return uni.getStorageSync(this.formKey);} catch (e) {console.error('读取草稿失败:', e);return null;}}// 清除草稿clearDraft() {try {uni.removeStorageSync(this.formKey);return true;} catch (e) {console.error('清除草稿失败:', e);return false;}}// 检查草稿是否有效(例如24小时内)isDraftValid(draft, maxAge = 24 * 60 * 60 * 1000) {if (!draft || !draft.timestamp) return false;return (Date.now() - draft.timestamp) < maxAge;}
}
二、恢复确认弹窗实现
1. 使用 UniApp 的模态框 API
// pages/your-form-page.vue
<script>
import { FormDraftManager } from '@/utils/storage.js';export default {data() {return {formData: {name: '',email: '',phone: '',// ...其他表单字段},draftManager: new FormDraftManager(),hasRecovered: false}},onLoad() {this.checkAndRecoverDraft();},onUnload() {// 页面卸载时自动保存(可选)this.autoSaveDraft();},methods: {// 检查并恢复草稿async checkAndRecoverDraft() {const draft = this.draftManager.getDraft();if (this.draftManager.isDraftValid(draft)) {// 显示恢复确认弹窗this.showRecoveryConfirm(draft);}},// 显示恢复确认弹窗showRecoveryConfirm(draft) {const formattedTime = this.formatTime(draft.timestamp);uni.showModal({title: '恢复填写进度?',content: `检测到您上次在 ${formattedTime} 有未提交的表单内容,是否恢复?`,confirmText: '恢复数据',cancelText: '重新开始',confirmColor: '#007AFF',success: (res) => {if (res.confirm) {this.restoreFormData(draft.data);} else {this.clearDraft();}}});},// 恢复表单数据restoreFormData(draftData) {this.formData = { ...this.formData, ...draftData };this.hasRecovered = true;// 显示成功提示uni.showToast({title: '数据恢复成功',icon: 'success',duration: 2000});},// 自动保存草稿autoSaveDraft() {// 检查表单是否有内容if (this.hasFormData()) {this.draftManager.saveDraft(this.formData);}},// 检查表单是否有数据hasFormData() {return Object.values(this.formData).some(value => value !== '' && value !== null && value !== undefined);},// 清除草稿clearDraft() {this.draftManager.clearDraft();},// 格式化时间formatTime(timestamp) {const date = new Date(timestamp);return `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;},// 表单提交async submitForm() {try {// 你的提交逻辑// await submitApi(this.formData);// 提交成功后清除草稿this.clearDraft();uni.showToast({title: '提交成功',icon: 'success'});} catch (error) {uni.showToast({title: '提交失败',icon: 'error'});}},// 手动保存草稿(可提供给用户操作)manualSaveDraft() {if (this.draftManager.saveDraft(this.formData)) {uni.showToast({title: '草稿已保存',icon: 'success'});}}}
}
</script>
三、实时自动保存(增强体验)
1. 防抖自动保存
// 在 data 中添加
data() {return {// ...其他数据autoSaveTimer: null}
},// 在 methods 中添加
methods: {// 输入时触发自动保存(防抖)onInput(field, value) {this.formData[field] = value;this.debouncedAutoSave();},// 防抖自动保存debouncedAutoSave() {if (this.autoSaveTimer) {clearTimeout(this.autoSaveTimer);}this.autoSaveTimer = setTimeout(() => {this.autoSaveDraft();}, 2000); // 2秒后自动保存},// 显示保存状态showSaveStatus() {// 可以在模板中显示保存状态this.saveStatus = '保存中...';setTimeout(() => {this.saveStatus = '已保存';setTimeout(() => {this.saveStatus = '';}, 2000);}, 500);}
}
四、模板部分
<template><view class="form-container"><!-- 保存状态提示 --><view v-if="saveStatus" class="save-status">{{ saveStatus }}</view><form @submit="submitForm"><view class="form-item"><text class="label">姓名</text><input class="input" v-model="formData.name" @input="onInput('name', $event.detail.value)"placeholder="请输入姓名" /></view><view class="form-item"><text class="label">邮箱</text><input class="input" v-model="formData.email" @input="onInput('email', $event.detail.value)"placeholder="请输入邮箱" type="email"/></view><view class="form-item"><text class="label">电话</text><input class="input" v-model="formData.phone" @input="onInput('phone', $event.detail.value)"placeholder="请输入电话" type="number"/></view><!-- 更多表单项... --><view class="form-actions"><button class="btn-save-draft" @click="manualSaveDraft" type="button">保存草稿</button><button class="btn-submit" form-type="submit">提交表单</button></view></form></view>
</template><style scoped>
.form-container {padding: 30rpx;
}.save-status {text-align: center;color: #07c160;font-size: 24rpx;margin-bottom: 20rpx;
}.form-item {margin-bottom: 40rpx;
}.label {display: block;margin-bottom: 10rpx;font-weight: bold;
}.input {border: 1px solid #ddd;border-radius: 8rpx;padding: 20rpx;font-size: 28rpx;
}.form-actions {display: flex;gap: 20rpx;margin-top: 60rpx;
}.btn-save-draft {flex: 1;background: #f8f9fa;color: #333;
}.btn-submit {flex: 2;background: #007AFF;color: white;
}
</style>