关于 frontend-patterns
面向 Rails 前端开发的模式指南,涵盖 Slim 模板、Simple Form、Stimulus 控制器和 Optics CSS。内容通过约定与示例说明视图组织、表单、交互和样式写法。
主要功能
- 01Slim 视图与局部模板约定
- 02使用 Simple Form 构建表单
- 03Stimulus 控制器实践
- 04Optics CSS 与 BEM 样式规范
适用场景
- 01编写 Rails 页面与可复用组件
- 02实现模型表单及搜索筛选表单
- 03添加 Stimulus 交互行为
- 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