You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails Turbo Stream无法通过Stimulus请求更新视图局部SVG

解决SVG点击后无刷新切换状态的问题

问题核心

后端记录已通过Stimulus请求成功更新,但前端SVG图标未自动切换,需手动刷新页面才能看到状态变化;且Stimulus发起的PATCH请求为multipart/form-data类型,与常规表单的application/x-www-form-urlencoded格式不一致。


解决方案

1. 修正Stimulus请求格式并添加前端DOM更新逻辑

修改trx_toggle_controller.js,将请求格式改为application/x-www-form-urlencoded,并在请求成功后直接更新SVG图标:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["icon"]

  toggleCleared() {
    const trxId = this.element.dataset.trxId
    const currentCleared = this.iconTarget.dataset.cleared === "true"

    fetch(`/trxes/${trxId}`, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').content
      },
      body: new URLSearchParams({
        trx: { cleared: !currentCleared }
      })
    })
    .then(response => response.json())
    .then(data => {
      this._updateIconState(data.cleared)
    })
  }

  _updateIconState(isCleared) {
    // 根据状态切换SVG内容,替换为你的实际SVG代码
    const clearedSvg = `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`
    const unclearedSvg = `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>`
    
    this.iconTarget.innerHTML = isCleared ? clearedSvg : unclearedSvg
    this.iconTarget.dataset.cleared = String(isCleared)
  }
}

2. 调整后端控制器返回JSON响应

修改TrxesController的update方法,返回更新后的cleared状态,供前端使用:

def update
  @trx = Trx.find(params[:id])
  if @trx.update(trx_params)
    render json: { cleared: @trx.cleared }
  else
    render json: { error: "更新失败" }, status: :unprocessable_entity
  end
end

private
def trx_params
  params.require(:trx).permit(:cleared)
end

3. 优化视图局部的标记结构

确保SVG容器带有Stimulus目标和状态数据属性,方便前端读取与更新:

# _trx.html.erb
<div data-controller="trx-toggle" data-trx-id="<%= trx.id %>">
  <span 
    data-trx-toggle-target="icon" 
    data-cleared="<%= trx.cleared %>"
    style="cursor: pointer;"
  >
    <%= trx.cleared ? 
      '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>' : 
      '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>' 
    %>
  </span>
</div>

关键说明

  • 前端状态切换必须手动触发:Stimulus不会自动同步后端更新到DOM,需在请求成功后直接修改SVG内容
  • 请求格式必须匹配:application/x-www-form-urlencoded是Rails默认的表单处理格式,避免后端解析异常
  • 用data-*属性存储当前状态:方便前端快速读取和更新状态标记

内容的提问来源于stack exchange,提问作者chug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:07:47