如何在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); } }
问题根源
- 循环生成了多个模态框,但
data-clickable_images-target="modal"只会绑定第一个模态框,导致每次点击都打开第一个模态框,显示第一张图。 - 没有将点击图片的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
相关产品推荐
相关产品推荐

