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

如何在Rails+Stimulus项目中实现点击图片后在模态框显示对应图片?

问题描述

我是JavaScript新手,通过Stimulus学习JS并使用Rails开发。尝试实现点击图库中的图片后,在模态框中显示对应图片,但模态框始终只显示图库的第一张图片,不知道如何动态获取点击图片的src来实现需求。


页面代码(index.html.erb)

<div class="container mb-5">
  <h1 class='headers'>This is my personal art page</h1>
  <div class='image_container' id='app' data-controller="clickable_images">
    <% @personals.each do |personal| %>
      <div class='img-box'>
        <button data-action="click->clickable_images#expandImage"><%= cl_image_tag personal.image.key, class: 'personal_img', data: { target: "image" } %></button>
      </div>

      <div class="modal" data-controller="slider" data-clickable_images-target="modal">
        <div class="modal-dialog">
          <div class="modal-content">
            <%= cl_image_tag personal.image.key %>
            <button data-action="click->slider#close">Close</button>
          </div>
        </div>
      </div>
    <% end %>
  </div>
</div>

Stimulus控制器:slider_controller.js

import { Controller } from "stimulus";

export default class extends Controller {

  open() {
    document.body.classList.add("modal-open");
    this.element.setAttribute("style", "display: block;");
    this.element.classList.add("show");
    document.body.innerHTML += '<div class="modal-backdrop fade show"></div>';
  }

  close() {
    document.body.classList.remove("modal-open");
    this.element.removeAttribute("style");
    this.element.classList.remove("show");
    document.getElementsByClassName("modal-backdrop")[0].remove();
  }
}

Stimulus控制器:clickable_images_controller.js

import { Controller } from "@hotwired/stimulus"

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

  expandImage(event) {
    let sliderController = this.application.getControllerForElementAndIdentifier(
      this.modalTarget,
      "slider"
    );

    sliderController.open();

    console.log(event.currentTarget);
  }
}

问题根源
  1. 循环生成了多个模态框,但data-clickable_images-target="modal"只会绑定第一个模态框,导致每次点击都打开第一个模态框,显示第一张图。
  2. 没有将点击图片的src传递给模态框,无法动态更新显示内容。
修复方案

第一步:复用单个模态框(移出循环)

不需要为每张图生成独立模态框,复用一个模态框更高效。修改页面代码:

<div class="container mb-5">
  <h1 class='headers'>This is my personal art page</h1>
  <div class='image_container' id='app' data-controller="clickable_images">
    <% @personals.each do |personal| %>
      <div class='img-box'>
        <!-- 通过data属性存储当前图片的src -->
        <button 
          data-action="click->clickable_images#expandImage"
          data-image-src="<%= cl_image_path(personal.image.key) %>"
        >
          <%= cl_image_tag personal.image.key, class: 'personal_img' %>
        </button>
      </div>
    <% end %>

    <!-- 单个模态框放在循环外部 -->
    <div class="modal" data-controller="slider" data-clickable_images-target="modal">
      <div class="modal-dialog">
        <div class="modal-content">
          <!-- 预留空img标签,后续动态替换src -->
          <img id="modal-image" src="" alt="Expanded image">
          <button data-action="click->slider#close">Close</button>
        </div>
      </div>
    </div>
  </div>
</div>

第二步:修改clickable_images控制器,传递图片src

在点击事件中读取图片src并更新模态框内容:

import { Controller } from "@hotwired/stimulus"

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

  expandImage(event) {
    // 获取点击按钮上存储的图片src
    const imageSrc = event.currentTarget.dataset.imageSrc;
    // 找到模态框中的img元素
    const modalImage = this.modalTarget.querySelector("#modal-image");
    // 更新模态框图片的src
    modalImage.src = imageSrc;
    
    // 打开模态框
    const sliderController = this.application.getControllerForElementAndIdentifier(
      this.modalTarget,
      "slider"
    );
    sliderController.open();
  }
}

第三步:优化slider控制器的backdrop创建(可选)

避免重复创建模态框遮罩层:

import { Controller } from "stimulus";

export default class extends Controller {

  open() {
    document.body.classList.add("modal-open");
    this.element.setAttribute("style", "display: block;");
    this.element.classList.add("show");
    
    // 仅在没有遮罩层时创建
    if (!document.querySelector(".modal-backdrop")) {
      const backdrop = document.createElement('div');
      backdrop.className = 'modal-backdrop fade show';
      document.body.appendChild(backdrop);
    }
  }

  close() {
    document.body.classList.remove("modal-open");
    this.element.removeAttribute("style");
    this.element.classList.remove("show");
    
    // 移除遮罩层(存在时才执行)
    const backdrop = document.querySelector(".modal-backdrop");
    if (backdrop) backdrop.remove();
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:39:54