자체 파괴 StimulusJS 컨트롤러

이 게시물은 Hotwire Summer의 일부입니다: Boring Rails 콘텐츠의 새 시즌!

때로는 약간의 UX 개선을 위해 약간의 JavaScript가 필요할 수 있습니다. 예전에는 풀스택 개발자가 작은 jQuery 스니펫을 페이지에 직접 드롭하는 경우가 많았습니다.

<script type="application/javascript">
  $(".flash-container").delay(5000).fadeOut()
  $(".items").last().highlight()
</script>


작업을 완료했지만 최고는 아니 었습니다.

Hotwire 앱에서 "자체 파괴"Stimulus 컨트롤러를 사용하여 동일한 결과를 얻을 수 있습니다.

자기 파괴?



자체 파괴 Stimulus 컨트롤러는 약간의 코드를 실행한 다음 this.element.remove() 를 호출하여 DOM에서 자신을 제거합니다.

예를 보자:

// app/javascript/controllers/scroll_to_controller.js
import { Controller } from '@hotwired/stimulus'

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

  connect() {
    this.targetElement.scrollIntoView()
    this.element.remove()
  }

  get targetElement() {
    return document.getElementById(this.locationValue)
  }
}


이 컨트롤러는 location 값을 받은 다음 페이지를 스크롤하여 해당 요소를 표시합니다.

<template
  data-controller="scroll-to"
  data-scroll-to-location-value="task_12345"></template>


자체 파괴 컨트롤러의 경우 it will not be displayed in the browser 이후 <template> 태그를 사용하는 것을 좋아하며 코드를 읽을 때 이것이 단지 빈 div 이 아니라는 좋은 신호입니다.

이 패턴은 Turbo Stream 응답에서 정말 잘 작동합니다.

새 작업을 만들기 위해 인라인 양식이 있는 작업 목록이 있다고 상상해 보세요. 양식을 제출한 다음 <turbo-stream>를 다시 보내 목록에 추가한 다음 새로 생성된 작업으로 페이지를 스크롤할 수 있습니다.

<%= turbo_stream.append :tasks, @task %>

<%= turbo_stream.append :tasks do %>
  <template
    data-controller="scroll-to"
    data-scroll-to-location-value="<% dom_id(@task) %>"></template>
<% end %>


그리고 Stimulus 컨트롤러에 약간의 JavaScript 기능을 포함하기 때문에 모든 수명 주기 이벤트가 처리됩니다. turbo:load 이벤트를 수신할 필요가 없으며 작동합니다.

이것을 다른 무엇에 사용할 수 있습니까?



형광펜



이 컨트롤러highlighter를 사용하여 무언가가 "선택"되었을 때 추가 스타일을 추가합니다.



<template
  data-controller="highlighter"
  data-highlighter-marker-value="<%= dom_id(task, :list_item) %>"
  data-highlighter-highlight-class="text-blue-600 bg-blue-100"></template>


Stimulusvaluesclasses API를 모두 사용함으로써 이 컨트롤러는 매우 재사용 가능합니다. DOM 요소 ID와 요소를 강조 표시하는 데 사용할 클래스를 지정할 수 있습니다.

// app/javascript/controllers/highlighter_controller.js
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
  static values = {
    marker: String
  }
  static classes = ["highlight"]

  connect() {
   this.markedElement.classList.add(...this.highlightClasses)
   this.element.remove()
  }

  get markedElement() {
    return document.getElementById(this.markerValue)
  }
}


초점을 잡아



작업을 빠르게 추가할 수 있는 양식에 grab-focus 컨트롤러를 사용합니다. 양식을 제출하면 작업이 생성되고 다음 작업에 대한 새 작업<form>이 동적으로 추가됩니다. 이 컨트롤러는 브라우저 포커스를 새 입력으로 원활하게 이동합니다.

Example of grab-focus controller

// app/javascript/controllers/grab_focus_controller.js
import { Controller } from '@hotwired/stimulus'

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

  connect() {
    this.grabFocus()
    this.element.remove()
  }

  grabFocus() {
    if (this.hasSelectorValue) {
      document.querySelector(this.selectorValue)?.focus()
    }
  }
}


분석 "비콘"



HEY에서 이 아이디어를 차용하여 페이지 분석을 추적하는 데 사용합니다. 페이지 보기를 기록하기 위해 백엔드를 ping한 다음 자체적으로 제거하는 페이지에 beacon를 추가합니다.

(멋있다면 Beacon Web API 을 사용할 수도 있지만 여기서는 단순성을 위해 PATCH 요청을 보냅니다!)

// app/javascript/controllers/beacon_controller.js
import { Controller } from '@hotwired/stimulus'
import { patch } from '@rails/request.js'

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

  connect() {
    patch(this.urlValue)
    this.element.remove()
  }
}


보다 깔끔한 API를 위해 Rails 보기 헬퍼에 이것을 래핑했습니다.

module AnalyticsHelper
  def tracking_beacon(url:)
    tag.template data: { controller: "beacon", beacon_url_value: url }
  end
end



<!-- Inside app/views/layouts/plan.html.erb -->
<%= tracking_beacon(url: plan_viewings_path(@plan)) %>



마무리



자동 소멸 Stimulus 컨트롤러는 클라이언트 측에서 전체 기능을 완전히 꺼내고 빌드할 필요 없이 JavaScript 동작을 추가하여 Hotwire 애플리케이션을 보강하는 좋은 방법입니다. 작고 단일 용도로 유지하면 여러 페이지와 다른 컨텍스트에서 재사용할 수 있습니다.

Stimulus 컨트롤러의 기존 수명 주기에 편승하여 Turbo Streams를 통해 콘텐츠를 변경하고 Turbo Drive로 페이지를 탐색할 때 예상대로 작동하도록 합니다.

좋은 웹페이지 즐겨찾기