使用HTML和StimulusJS实现手风琴仅首个生效的问题求助
手风琴组件问题修复方案
问题根源
- 控制器作用域错误:你把所有手风琴项都放在同一个
data-controller="dropdown"容器下,导致所有项共享一个控制器实例。Stimulus中this.dropTarget这类单数target只会匹配第一个元素,所以只有第一个手风琴能响应操作,其余项找不到对应target而失效。 - 重复绑定点击事件:
onToggle方法里手动给所有按钮绑定点击事件完全多余——你已经通过data-action="click->dropdown#onToggle"完成了事件绑定,重复绑定会导致逻辑混乱。 - 样式操作不严谨:直接替换
className会覆盖元素原有样式类,容易导致样式丢失,应该用类列表的增删操作来控制样式。
修复后的完整代码
<script src="https://cdn.tailwindcss.com"></script> <script type="module"> import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js" window.Stimulus = Application.start() Stimulus.register("dropdown", class extends Controller { static targets = ["background", "drop", "expand"]; connect() { console.log("Drop Down connected"); } initialize() { this.isOpen = false; // 初始为关闭状态,符合默认隐藏逻辑 } onToggle() { this.isOpen ? this.hide() : this.show(); this.isOpen = !this.isOpen; }; show() { // 用classList增删类,保留原有样式 this.dropTarget.classList.remove("hidden"); this.dropTarget.classList.add("block", "w-full", "text-base", "font-light", "pt-3"); this.backgroundTarget.classList.add("bg-[#F0F0F0]", "mb-2"); this.backgroundTarget.classList.remove("bg-white", "-mb-2"); this.expandTarget.textContent = "-"; console.log("dropdown is active"); } hide() { this.dropTarget.classList.add("hidden"); this.dropTarget.classList.remove("block", "w-full", "text-base", "font-light", "pt-3"); this.backgroundTarget.classList.add("bg-white", "-mb-2"); this.backgroundTarget.classList.remove("bg-[#F0F0F0]", "mb-2"); this.expandTarget.textContent = "+"; console.log("dropdown is closed"); } }) </script> <div class="w-full flex flex-col gap-12 md:flex-row sm:max-w-[400px] md:max-w-[450px] lg:max-w-[500px] text-[#868686]"> <div class="md:min-h-[450px] w-full mt-3"> <h4 class="text-4xl font-semibold px-4 pb-3">FAQ's</h4> <!-- 每个手风琴项单独绑定控制器,实现独立控制 --> <div data-controller="dropdown" data-dropdown-target="background" class="py-4 px-4"> <div data-action="click->dropdown#onToggle" class="cursor-pointer flex justify-between items-center"> <h5 class="text-xl font-bold">Waar hebben jullie nieuwe tuinen aangelegd? </h5><span data-dropdown-target="expand" class="font-light text-[18px] self-start">+</span> </div> <p data-dropdown-target="drop" class="hidden">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </div> <div data-controller="dropdown" data-dropdown-target="background" class="py-4 px-4"> <div data-action="click->dropdown#onToggle" class="cursor-pointer flex justify-between items-center"> <h5 class="text-xl font-bold">Waar moet een goede hovenier aan voldoen?</h5><span data-dropdown-target="expand" class="font-light text-[18px] self-start">+</span> </div> <p data-dropdown-target="drop" class="hidden ">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </div> <div data-controller="dropdown" data-dropdown-target="background" class="py-4 px-4"> <div data-action="click->dropdown#onToggle" class="cursor-pointer flex justify-between items-center"> <h5 class="text-xl font-bold">Wat kost de aanleg van een nieuwe tuin? </h5><span data-dropdown-target="expand" class="font-light text-[18px] self-start">+</span> </div> <p data-dropdown-target="drop" class="hidden">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </div> <div data-controller="dropdown" data-dropdown-target="background" class="py-4 px-4"> <div data-action="click->dropdown#onToggle" class="cursor-pointer flex justify-between items-center"> <h5 class="text-xl font-bold">Zijn de afspraken vrijblijvend?</h5><span data-dropdown-target="expand" class="font-light text-[18px] ml-auto self-start">+</span> </div> <p data-dropdown-target="drop" class="hidden">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </div> </div> </div>
关键改动说明
- 独立控制器实例:将
data-controller="dropdown"移到每个手风琴项的容器上,让每个项拥有独立的控制器实例,各自管理自己的展开/收起状态。 - 移除冗余事件绑定:删掉
onToggle中手动添加点击事件的代码,完全依赖Stimulus的data-action机制。 - 优化样式操作:使用
classList.add()/classList.remove()替代直接赋值className,避免丢失元素原有样式。 - 修正初始状态:将
isOpen初始值设为false,匹配手风琴默认隐藏的需求。 - 清理无用target:移除不需要的
buttonTarget配置,因为按钮已通过data-action绑定事件,无需作为target管理。
内容的提问来源于stack exchange,提问作者moses ubah
相关产品推荐
相关产品推荐

