mcpField
F
form-auto-save

form-auto-save

github.com/rolemodel开发737 次安装1 天前更新
代码仓库

关于 form-auto-save

Form Auto Save Skill 介绍一种 Stimulus 模式,可在 Rails 表单发生更改后自动提交,并通过防抖减少请求。它面向构建长文本或多字段编辑界面的开发者。

主要功能

  1. 01防抖式自动提交表单
  2. 02默认延迟 8 秒且可配置
  3. 03监听 change 和 lexxy:change
  4. 04提供程序化取消与提交方法
  5. 05通过保存计数测试系统规格

适用场景

  1. 01为长文本编辑页面添加自动保存
  2. 02保存富文本字段的更改
  3. 03避免固定休眠计时器来测试保存

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rolemodel/rolemodel-skills --skill form-auto-save

安装后在 Claude Code 中输入/form-auto-save确认已加载。

详细介绍

表单自动保存技能

概述

表单自动保存模式会在用户输入发生变化后自动提交表单,并使用防抖机制避免向服务器发送过多请求。这能为编辑表单的用户带来流畅的“自动保存”体验。

适用场景

  • 用户期望自动保存的长篇内容编辑界面
  • 包含富文本编辑器或多个字段的表单
  • 用户可能离开页面并期望更改得以保留的编辑页面
  • 适合逐步保存、无需显式点击“保存”按钮的表单

实现

1. Stimulus 控制器

此模式使用 Stimulus 控制器(form-auto-save)处理自动保存逻辑。

控制器位置: app/javascript/controllers/form_auto_save_controller.js

主要功能:

  • 防抖时间为 8 秒(可通过 static DEBOUNCE_TIME 配置)
  • 监听 change 和 lexxy:change 事件(用于自定义组件)
  • 使用被动事件监听器以提升性能
  • 提供 cancel() 和 submit() 方法,用于编程控制
  • 在 countValue 中统计成功保存的次数,系统规格测试会等待此值变化

控制器代码模式:

import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
  static DEBOUNCE_TIME = 8000
  static values = { count: Number }

  connect() {
    this.element.addEventListener('change', this.#debounceSubmit.bind(this), { passive: true })
    this.element.addEventListener('lexxy:change', this.#debounceSubmit.bind(this), { passive: true })
    this.element.addEventListener('turbo:submit-end', ({ detail }) => { if (detail.success) this.countValue++ })
  }

  cancel() {
    clearTimeout(this.debounceTimer)
  }

  submit() {
    this.element.requestSubmit()
  }

  #debounceSubmit() {
    this.#debounce(this.submit.bind(this))
  }

  #debounce(callback) {
    clearTimeout(this.debounceTimer)
    this.debounceTimer = setTimeout(callback, this.constructor.DEBOUNCE_TIME)
  }
}
2. 视图集成

使用 Stimulus 数据属性将控制器附加到表单元素。

必需属性:

  • data: { controller: 'form-auto-save' } - 附加 Stimulus 控制器
  • data: { turbo_permanent: true } - 可选,但建议启用,以便在 Turbo 导航期间保留表单状态

示例(Slim):

= simple_form_for resource, html: { data: { controller: 'form-auto-save', turbo_permanent: true } } do |f|
  = f.input :field_name
  = f.rich_text_area :content

重要注意事项

防抖时间
  • 默认值:8 秒(8000ms)
  • 如有需要,可在控制器中通过 static DEBOUNCE_TIME 调整
  • 请考虑用户体验:时间过短 = 请求过多;时间过长 = 更改可能丢失
事件监听器
  • 监听 change 事件(标准 HTML 输入项的更改)
  • 监听 lexxy:change 事件(自定义组件事件,例如富文本编辑器)
  • 使用被动监听器以提升滚动性能
Turbo Permanent
  • turbo_permanent: true 会在 Turbo 导航期间保留表单元素
  • 可避免用户导航时丢失未保存的更改
  • 对于带有自动保存功能的表单,此设置对保留防抖计时器至关重要
表单验证
  • 确保后端验证能够妥善处理部分保存
  • 考虑是否所有字段都必须填写,还是允许部分完成
  • 如果自动保存失败,请提供清晰的错误反馈

测试

应等待控制器的 countValue,而不是使用 sleep 计时器。当 Turbo 报告提交成功时,该值会递增,因此它涵盖了防抖等待和请求往返时间。turbo_permanent: true 会在响应重定向后保留表单及其计数值。

自动保存辅助模块

文件: spec/support/helpers/form_auto_save_helper.rb

module FormAutoSaveHelper
  def expect_auto_save
    form = find("[data-controller~='form-auto-save']")
    count = form['data-form-auto-save-count-value'].to_i
    yield
    expect(page).to have_css("[data-form-auto-save-count-value='#{count + 1}']", wait: 10)
  end
end

在 spec/support/helpers.rb 中使用 c.include FormAutoSaveHelper, type: :system 将其引入系统规格测试。wait: 必须长于 DEBOUNCE_TIME。

系统规格测试示例
require 'rails_helper'

RSpec.describe 'Form Auto Save', :js do
  it 'automatically saves form after changes' do
    resource = create(:resource)
    visit edit_resource_path(resource)

    expect_auto_save do
      fill_in 'Field name', with: 'Updated value'
    end

    expect(resource.reload.field_name).to eq('Updated value')
  end

  it 'debounces multiple rapid changes' do
    resource = create(:resource)
    visit edit_resource_path(resource)

    expect_auto_save do
      fill_in 'Field name', with: 'First'
      fill_in 'Field name', with: 'Second'
      fill_in 'Field name', with: 'Final'
    end

    # Should only save once with final value
    expect(resource.reload.field_name).to eq('Final')
  end
end

常见问题

问题:表单不会自动保存

检查:

  • 控制器是否已正确附加:data: { controller: 'form-auto-save' }
  • 表单字段是否会触发 change 事件(文本输入框可能需要失焦)
  • 浏览器开发者工具中的网络请求
问题:请求过多

解决方案:

  • 增大 DEBOUNCE_TIME
  • 检查是否存在不必要的事件触发
  • 确认防抖逻辑正常工作
问题:导航时更改丢失

解决方案:

  • 为表单添加 turbo_permanent: true
  • 确保表单具有稳定的 id 属性
  • 考虑添加“存在未保存更改”警告

相关模式

  • 动态表单: 随表单填写而变化的字段属于 dynamic-forms 技能(turbo_form gem)
  • Stimulus 值: 如果需要为不同实例设置防抖时间
  • 表单验证: 可考虑结合自动保存使用内联验证

参考资料

评论

支持 Markdown