stimulus-controllers

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Stimulus Controllers

Stimulus控制器

Overview

概述

Stimulus controllers provide modular JavaScript functionality connected to HTML via data attributes. After creating a new controller, you must register it in the index.js file.
Stimulus控制器提供模块化的JavaScript功能,通过data属性与HTML关联。创建新控制器后,必须在index.js文件中注册它。

Creating a New Controller

创建新控制器

1. Create the Controller File

1. 创建控制器文件

Create a new controller in
app/javascript/controllers/
:
javascript
// app/javascript/controllers/example_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["element"]
  static values = { name: String }

  connect() {
    // Called when controller is connected to DOM
  }

  disconnect() {
    // Called when controller is disconnected from DOM
  }

  // Action methods
  handleClick(event) {
    event.preventDefault()
    // Your logic here
  }
}
app/javascript/controllers/
目录下创建新控制器:
javascript
// app/javascript/controllers/example_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["element"]
  static values = { name: String }

  connect() {
    // 控制器连接到DOM时调用
  }

  disconnect() {
    // 控制器从DOM断开连接时调用
  }

  // 动作方法
  handleClick(event) {
    event.preventDefault()
    // 此处编写你的逻辑
  }
}

2. Register the Controller

2. 注册控制器

CRITICAL: After creating a new controller, run:
bash
bin/rails stimulus:manifest:update
This automatically updates
app/javascript/controllers/index.js
to register your controller.
Manual Registration (if needed):
javascript
import ExampleController from "./example_controller"
application.register("example", ExampleController)
Controller name in HTML uses kebab-case:
data-controller="example"
重要提示:创建新控制器后,运行以下命令:
bash
bin/rails stimulus:manifest:update
这会自动更新
app/javascript/controllers/index.js
以注册你的控制器。
手动注册(如有需要):
javascript
import ExampleController from "./example_controller"
application.register("example", ExampleController)
HTML中的控制器名称使用短横线分隔式(kebab-case):
data-controller="example"

3. Use in HTML

3. 在HTML中使用

Connect the controller to HTML elements:
slim
.container data-controller="example" data-example-name-value="test"
  button data-action="click->example#handleClick" Click Me
  div data-example-target="element" Target Element
将控制器连接到HTML元素:
slim
.container data-controller="example" data-example-name-value="test"
  button data-action="click->example#handleClick" 点击我
  div data-example-target="element" 目标元素

Naming Conventions

命名规范

  • File:
    example_controller.js
    (snake_case)
  • Class:
    export default class extends Controller
  • Registration:
    "example"
    (kebab-case)
  • HTML:
    data-controller="example"
    (kebab-case)
  • Multi-word:
    bulk_submit_controller.js
    "bulk-submit"
  • 文件
    example_controller.js
    (下划线分隔式snake_case)
  • export default class extends Controller
  • 注册名称
    "example"
    (短横线分隔式kebab-case)
  • HTML
    data-controller="example"
    (短横线分隔式kebab-case)
  • 多词命名
    bulk_submit_controller.js
    "bulk-submit"

Key Concepts

核心概念

Targets

目标(Targets)

Reference specific DOM elements:
javascript
static targets = ["input", "output"]

// Access in methods:
this.inputTarget        // First matching element
this.inputTargets       // All matching elements
this.hasInputTarget     // Boolean check
引用特定DOM元素:
javascript
static targets = ["input", "output"]

// 在方法中访问:
this.inputTarget        // 第一个匹配的元素
this.inputTargets       // 所有匹配的元素
this.hasInputTarget     // 布尔值检查

Values

值(Values)

Type-safe data attributes:
javascript
static values = {
  url: String,
  count: Number,
  active: Boolean,
  items: Array,
  config: Object
}

// Access in methods:
this.urlValue
this.countValue

// Watch for changes:
urlValueChanged(newUrl, oldUrl) {
  // Called when value changes
}
类型安全的data属性:
javascript
static values = {
  url: String,
  count: Number,
  active: Boolean,
  items: Array,
  config: Object
}

// 在方法中访问:
this.urlValue
this.countValue

// 监听变化:
urlValueChanged(newUrl, oldUrl) {
  // 值变化时调用
}

Actions

动作(Actions)

Connect events to methods:
html
<!-- Basic action -->
data-action="click->example#save"

<!-- Multiple actions -->
data-action="click->example#save submit->example#submit"

<!-- Custom events -->
data-action="example:refresh->example#reload"

<!-- Event modifiers -->
data-action="submit->example#save:prevent"
将事件与方法关联:
html
<!-- 基础动作 -->
data-action="click->example#save"

<!-- 多个动作 -->
data-action="click->example#save submit->example#submit"

<!-- 自定义事件 -->
data-action="example:refresh->example#reload"

<!-- 事件修饰符 -->
data-action="submit->example#save:prevent"

Classes

类(Classes)

Manage CSS classes:
javascript
static classes = ["active", "hidden"]

// Use in methods:
this.element.classList.add(this.activeClass)
this.element.classList.remove(this.hiddenClass)
管理CSS类:
javascript
static classes = ["active", "hidden"]

// 在方法中使用:
this.element.classList.add(this.activeClass)
this.element.classList.remove(this.hiddenClass)

Common Patterns

常见模式

Form Validation

表单验证

javascript
export default class extends Controller {
  static targets = ["form", "submit"]

  validate() {
    const isValid = this.formTarget.checkValidity()
    this.submitTarget.disabled = !isValid
  }
}
javascript
export default class extends Controller {
  static targets = ["form", "submit"]

  validate() {
    const isValid = this.formTarget.checkValidity()
    this.submitTarget.disabled = !isValid
  }
}

Toggle Visibility

切换可见性

javascript
export default class extends Controller {
  static targets = ["content"]
  static classes = ["hidden"]

  toggle() {
    this.contentTarget.classList.toggle(this.hiddenClass)
  }
}
javascript
export default class extends Controller {
  static targets = ["content"]
  static classes = ["hidden"]

  toggle() {
    this.contentTarget.classList.toggle(this.hiddenClass)
  }
}

AJAX Updates

AJAX更新

javascript
export default class extends Controller {
  static values = { url: String }

  async refresh() {
    const response = await fetch(this.urlValue)
    const html = await response.text()
    this.element.innerHTML = html
  }
}
javascript
export default class extends Controller {
  static values = { url: String }

  async refresh() {
    const response = await fetch(this.urlValue)
    const html = await response.text()
    this.element.innerHTML = html
  }
}

Testing

测试

Test Stimulus controllers in system specs:
ruby
it 'handles interaction', :js do
  visit page_path

  click_button 'Toggle'

  expect(page).to have_css('[data-controller="example"]')
end
在系统测试用例中测试Stimulus控制器:
ruby
it 'handles interaction', :js do
  visit page_path

  click_button 'Toggle'

  expect(page).to have_css('[data-controller="example"]')
end

Troubleshooting

故障排除

Controller not working?
  1. Verify controller is registered in
    index.js
  2. Run
    bin/rails stimulus:manifest:update
  3. Check browser console for errors
  4. Verify data attribute spelling (kebab-case)
  5. Ensure JavaScript is enabled in tests (
    :js
    tag)
Targets not found?
  • Check target name in
    static targets
    matches HTML
  • Use
    hasXxxTarget
    to verify existence before accessing
  • Ensure target element is in controller scope
控制器无法工作?
  1. 验证控制器已在
    index.js
    中注册
  2. 运行
    bin/rails stimulus:manifest:update
  3. 检查浏览器控制台是否有错误
  4. 验证data属性的拼写(短横线分隔式kebab-case)
  5. 确保测试中启用了JavaScript(
    :js
    标签)
找不到目标?
  • 检查
    static targets
    中的目标名称与HTML是否匹配
  • 在访问目标前使用
    hasXxxTarget
    验证其是否存在
  • 确保目标元素在控制器的作用域内

Related Skills

相关技能

  • frontend-patterns - HTML and CSS patterns
  • turbo-fetch - Dynamic form updates
  • testing-patterns - Testing JavaScript features
  • 前端模式 - HTML和CSS模式
  • Turbo Fetch - 动态表单更新
  • 测试模式 - JavaScript功能测试