uniapp 防止长表单数据丢失方案,缓存表单填写内容,放置卡退或误操作返回。

防止长表单数据丢失方案,缓存表单填写内容,放置卡退或误操作返回。

一、存储方案(多端兼容)

1. 使用 UniApp 的数据存储 API

javascript 复制代码
// 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

javascript 复制代码
// 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. 防抖自动保存

javascript 复制代码
// 在 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);
  }
}

四、模板部分

javascript 复制代码
<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>
相关推荐
Amy_yang1 分钟前
js 封装时间格式化,将单位有秒(s)的数据转换为'00:00:00'格式
javascript
interception2 分钟前
爬虫js逆向,jsdom补环境,抖音,a_bogus
javascript·爬虫·python
小璞3 分钟前
一、React Fiber 架构与任务调度详解
前端·react.js·前端框架
小璞3 分钟前
四、虚拟 DOM 与 Diff 算法:架构设计的智慧
前端·react.js·前端框架
南蓝4 分钟前
【AI 日记】调用大模型的时候如何按照 sse 格式输出
前端·人工智能
一树论6 分钟前
浏览器插件开发经验分享二:如何处理日期控件
前端·javascript
小璞7 分钟前
六、React 并发模式:让应用"感觉"更快的架构智慧
前端·react.js·架构
Yanni4Night8 分钟前
LogTape:零依赖的现代JavaScript日志解决方案
前端·javascript
疯狂踩坑人8 分钟前
Node写MCP入门教程
前端·agent·mcp
重铸码农荣光8 分钟前
一文吃透 ES6 Symbol:JavaScript 里的「独一无二」标识符
前端·javascript