mcpField
F
frontend-patterns

frontend-patterns

github.com/rolemodel开发739 次安装今天更新
代码仓库

关于 frontend-patterns

面向 Rails 前端开发的模式指南,涵盖 Slim 模板、Simple Form、Stimulus 控制器和 Optics CSS。内容通过约定与示例说明视图组织、表单、交互和样式写法。

主要功能

  1. 01Slim 视图与局部模板约定
  2. 02使用 Simple Form 构建表单
  3. 03Stimulus 控制器实践
  4. 04Optics CSS 与 BEM 样式规范

适用场景

  1. 01编写 Rails 页面与可复用组件
  2. 02实现模型表单及搜索筛选表单
  3. 03添加 Stimulus 交互行为
  4. 04按 BEM 组织组件样式

安装

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

$npx skills add https://github.com/rolemodel/rolemodel-skills --skill frontend-patterns

安装后在 Claude Code 中输入/frontend-patterns确认已加载。

附带文件references/EXAMPLES.md

详细介绍

前端模式

使用 Slim 模板、Simple Form、Stimulus 控制器和 Optics CSS 构建 Rails 前端。

技术栈: Slim(HTML)• Simple Form(表单)• Stimulus(JavaScript)• Optics(CSS)

详细代码示例请参阅 references/EXAMPLES.md。

Slim 模板

核心约定
  • 使用 Ruby 3+ 语法(例如,使用 : 的关键字参数)
  • 尽量减少视图逻辑——将其提取到辅助方法或局部模板中
  • 始终在操作周围添加策略检查(例如,编辑/删除链接)
  • 绝不使用内联样式
  • 将重复的标记提取到局部模板中(DRY 原则)
  • 始终使用带关键字参数的局部变量:render 'partial', user:, active: true
辅助方法与局部模板

适用于辅助方法的场景:

  • 带条件文本/类名的单个元素
  • 数据格式化(日期、货币)
  • 无状态逻辑
  • 示例:status_badge(status)

适用于局部模板的场景:

  • 多元素结构
  • 可复用 UI 组件
  • 集合渲染
  • 示例:_form.html.slim、_user_card.html.slim

规则: 单个元素用辅助方法;结构/布局用局部模板。

局部模板组织
app/views/
  resource_name/
    index.html.slim           # Main views
    _form.html.slim           # Forms (shared by new/edit)
    _resource_name.html.slim  # Individual item
  shared/
    _status_badge.html.slim   # Cross-feature components
常见模式
-# Conditional classes
.card class=class_names('card--active': active, 'card--urgent': urgent)

-# Partial with locals
= render 'user_card', user:, show_actions: true

-# Collection rendering
= render partial: 'item', collection: @items

-# Conditional rendering
- if policy(@resource).update?
  = link_to 'Edit', edit_path(@resource)

Simple Form

始终使用 Simple Form。 绝不使用 form_with 或 form_for。

基本表单

模型表单:

= simple_form_for @user do |f|
  = f.input :name
  = f.input :email, required: true
  
  .form__actions
    = link_to 'Cancel', :back, class: 'btn btn--outline'
    = f.submit 'Save', class: 'btn btn--primary'

非模型表单(搜索、筛选、批量操作):

= simple_form_for :search, url: search_path, method: :get do |f|
  = f.input :query
  = f.submit 'Search', class: 'btn btn--primary'

重要: :symbol 表单会嵌套参数:params.dig(:search, :query)

常见输入类型
类型示例
文本= f.input :name
文本区域= f.input :description, as: :text, input_html: { rows: 4 }
关联= f.association :project, collection: @projects, prompt: 'Select...'
选择框= f.input :type, collection: @project_types, prompt: 'Select...'
布尔值= f.input :active, as: :boolean
日期= f.input :start_date, as: :date
隐藏= f.hidden_field :organization_id, value: current_user.organization_id
输入选项
  • placeholder: - 占位文本
  • label: - 自定义标签
  • hint: - 输入框下方的帮助文本
  • required: true - 标记为必填
  • disabled: true - 禁用输入框
  • input_html: {} - 输入元素的 HTML 属性
  • wrapper_html: {} - 包装 div 的 HTML 属性
集合
/ Basic collection
= f.input :category_id, collection: @categories

/ Custom label/value methods
= f.input :project_id, 
  collection: @projects,
  label_method: :name,
  value_method: :id,
  prompt: 'Select project...'
特殊表单模式

批量操作表单:

= simple_form_for :bulk_action, url: bulk_path, method: :post, html: { id: 'bulk-form' } do |f|
  = f.button 'Approve Selected', class: 'btn btn--primary'

-# Checkboxes reference form
= check_box_tag 'entry_ids[]', entry.id, false, form: 'bulk-form'

带外部提交按钮的模态框表单:

= simple_form_for @record, html: { id: 'modal-form' }, data: { turbo_frame: '_top' } do |f|
  = f.input :reason, as: :text, input_html: { rows: 3, required: true }

-# In modal footer
= button_tag 'Submit', type: 'submit', form: 'modal-form', class: 'btn btn--primary'
表单选项
  • html: {} - 表单元素的 HTML 属性
  • data: {} - 数据属性(例如,Turbo、Stimulus)
  • url: - 表单提交 URL(:symbol 表单必填)
  • method: - HTTP 方法(:get、:post、:patch、:delete)

复杂表单示例请参阅 references/EXAMPLES.md。

Stimulus 控制器

使用 Stimulus 框架实现 JavaScript 交互。

控制器结构
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["output", "input"]
  static values = { url: String, delay: Number }
  static classes = ["hidden", "active"]

  connect() {
    // Initialization when controller connects to DOM
  }

  disconnect() {
    // Cleanup when controller disconnects
  }

  action(event) {
    // Action methods called from HTML
  }
}
在 Slim 中使用
.component data-controller="example" data-example-url-value="/api/endpoint"
  input data-example-target="input" data-action="input->example#search"
  .results data-example-target="output"
最佳实践
  • 每种行为使用一个控制器(专注且可组合)
  • 使用数据属性进行配置
  • 在 HTML 中使用 kebab-case 命名控制器
  • 保持控制器简洁且易于测试
  • 在 disconnect() 中清理资源(计时器、监听器)

完整控制器示例请参阅 references/EXAMPLES.md。

CSS 与 Optics

指南
  • 尽量减少自定义 CSS,并将其限定在组件范围内
  • 绝不使用内联样式
  • 强烈不建议使用工具类。应使用 BEM(块、元素、修饰符)结构。
  • 使用 class_names 辅助方法设置条件类名
常见模式
/ Custom component with BEM
.time-entry.time-entry--running
  .time-entry__header
    h3.time-entry__title = entry.description
  .time-entry__body
    span.time-entry__duration = entry.duration
条件类名
/ Using class_names helper
.card class=class_names(
  'card--active': @record.active?,
  'card--featured': @record.featured?
)

快速参考

表单操作模式:

.form__actions
  = link_to 'Cancel', :back, class: 'btn btn--outline'
  = f.submit 'Save', class: 'btn btn--primary'

空状态:

- if @items.empty?
  = render 'shared/empty_state', title: 'No items', message: 'Create your first item.'

授权检查:

- if policy(@resource).update?
  = link_to 'Edit', edit_path(@resource), class: 'btn'

Turbo 确认:

= button_to 'Delete', path, method: :delete, data: { turbo_confirm: 'Are you sure?' }

评论

支持 Markdown