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>
相关推荐
ObjectX前端实验室4 小时前
LLM流式输出完全解析之socket
前端
f 查看所有勋章4 小时前
六轴工业机器人可视化模拟平台 (Vue + Three.js + Blender)
javascript·vue.js·机器人
ObjectX前端实验室4 小时前
ChatGPT流式输出完全解析之SSE
前端·人工智能
沐曦可期4 小时前
标准编码与算法
javascript·python
又是忙碌的一天4 小时前
前端学习 JavaScript(2)
前端·javascript·学习
2501_915106324 小时前
JavaScript编程工具有哪些?老前端的实用工具清单与经验分享
开发语言·前端·javascript·ios·小程序·uni-app·iphone
GISer_Jing4 小时前
计算机基础——浏览器、算法、计算机原理和编译原理等
前端·javascript·面试
我的xiaodoujiao4 小时前
从 0 到 1 搭建 Python 语言 Web UI自动化测试学习系列 8--基础知识 4--常用函数 2
前端·python·测试工具·ui
蓝瑟5 小时前
React 项目实现拖拽排序功能,如何在众多库中选对 “它”
前端·javascript·react.js