为什么我的手风琴无法使用 HTML 和 Stimulusjs 运行

1 stimulusjs stimulus-reflex

请让我需要帮助来使这个手风琴工作,我对 StimulusJS 不太熟悉。第一个手风琴工作正常,但其余的没有反应。我在这里附上了一段代码,请让我知道我做错了什么,谢谢。

script 标签包含stimulusjs 代码。请留下您的意见,我将不胜感激。

<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", "button"];
    static values = { accordionValue: Number };
    connect() {
        console.log("Drop Down connected");
    }

    initialize() {
        this.isOpen = true;
    }

    onToggle = (e) => {
        Array.prototype.forEach.call(this.buttonTargets, function (element, index) {
            element.addEventListener("click", function () {
                console.log(index)
            })
        })
        this.isOpen ? this.show() : this.hide();
        this.isOpen = !this.isOpen;
    };

    show() {
        this.dropTarget.className = "block w-full text-base font-light pt-3";
        this.backgroundTarget.className = "bg-[#F0F0F0] mb-2 py-6 px-4";
        this.expandTarget.innerHTML = "-";
        console.log("dropdown is active");
    }

    hide() {
        this.dropTarget.className = "hidden";
        this.backgroundTarget.className = "bg-white -mb-2 w-full py-6 px-4";
        this.expandTarget.innerHTML = "+";
        console.log("dropdown is closed");
    }
    })
  </script>

<div data-controller="dropdown" 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-dropdown-target="background" class=" py-4 px-4">
      <div data-action="click->dropdown#onToggle" data-dropdown-target="button" 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-dropdown-target="background" class=" py-4 px-4">
      <div data-action="click->dropdown#onToggle" data-dropdown-target="button" 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-dropdown-target="background" class="py-4 px-4">
      <div data-action="click->dropdown#onToggle" data-dropdown-target="button" 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-dropdown-target="background" class="py-4 px-4">
      <div data-action="click->dropdown#onToggle" data-dropdown-target="button" 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>
Run Code Online (Sandbox Code Playgroud)

LB *_*ton 8

首先 - 从 HTML 开始

Stimulus 文档提供了很好的指南,其中一个关键原则是“从 HTML 开始”

所有现代浏览器都支持 HTMLdetails公开元素,您可以在 MDN 站点上找到真正可靠的文档。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details

使用 Tailwind 你可以走得很远,但你可能需要添加一个插件来根据open 属性设置样式。

对于样式,请参见

如果没有 Tailwind,这可能会容易一些,但这取决于你。

无需编写一行 JavaScript 即可尽可能接近,这是一个样式精美的单个手风琴项目,无需额外代码即可打开和关闭。

使用原生 HTML 元素的主要好处是

  • 需要维护的代码越少越好。
  • 迫使您考虑可访问性和键盘控制,而不是滚动自己的“按钮”,例如那些不是真正按钮的东西并破坏可访问性。
  • 可能足以按原样离开并继续,您可能不需要“打开其他内容时关闭其他内容”功能,并且您可以继续处理项目中的其他内容。

其次 - 用 Stimulus 填补造型空白

  • 您可能会发现必须使用一些 JavaScript 来添加/删除某些类,请尽力避免这种情况,但如果您必须使用上面的代码方法就足够接近了。
  • 您可能希望使用刺激类方法更明确地了解在元素上使用哪些类https://stimulus.hotwired.dev/reference/css-classes

最后 - 添加类似手风琴的行为

  • 假设您想要某种行为,例如Bootstrap 手风琴,其中展开一项将折叠任何已打开的其他项。
  • 下面是最简单的 JavaScript,它具有一个手风琴控制器,当一个项目打开时,该控制器会关闭所有其他项目(目标)。
  • 当调用该方法时toggle,它会读取该事件target,然后计算出该事件是打开还是关闭。如果它正在打开,我们将检查所有其他手风琴项目目标并关闭它们。
import { Controller } from '@hotwired/stimulus';

class AccordionController extends Controller {
  static targets = ['item'];

  toggle({ target }) {
    const isOpening = target.hasAttribute('open');

    if (isOpening) {
      // if opening - close the others
      this.itemTargets.forEach((item) => {
        if (item === target) return;
        item.removeAttribute('open');
      });
    }
  }
}

export default AccordionController;
Run Code Online (Sandbox Code Playgroud)
  • 在 HTML 中,我们data-controller="accordion"在外部容器上声明。
  • 对于每个details元素,我们添加两个属性:
    • data-accordion-target="item"- 将此details元素的范围限定为手风琴控制器的this.itemTargets数组。
    • data-action="toggle->accordion#toggle"- 这为内置事件添加了一个事件侦听器details toggle,请注意,该事件不会冒泡(与 不同click),因此我们在每个details元素上都需要它。
<section class="prose m-5" data-controller="accordion">
  <h2>Multiple 'details' element into an accordion</h2>
  <details
    class="py-4 px-4"
    data-action="toggle->accordion#toggle"
    data-accordion-target="item"
    >
    <summary
      class="flex justify-between items-center text-xl font-bold
      cursor-pointer">
      Section A
    </summary>
    <div class="bg-[#F0F0F0] mb-2 py-6 px-4">
      Content
    </div>
  </details>
  <details
    class="py-4 px-4"
    data-action="toggle->accordion#toggle"
    data-accordion-target="item"
    >
    <summary
      class="flex justify-between items-center text-xl font-bold
      cursor-pointer">
      Section B
    </summary>
    <div class="bg-[#F0F0F0] mb-2 py-6 px-4">
      Content
    </div>
  </details>
  <details
    class="py-4 px-4"
    data-action="toggle->accordion#toggle"
    data-accordion-target="item"
    >
    <summary
      class="flex justify-between items-center text-xl font-bold
      cursor-pointer">
      Section C
    </summary>
    <div class="bg-[#F0F0F0] mb-2 py-6 px-4">
      Content
    </div>
  </details>
</section>
Run Code Online (Sandbox Code Playgroud)

一般提示

  • 切勿将 a 用于div可点击的内容,这只会给您带来困难,请始终使用 a buttonwith type="button"
  • 可访问性和元素之间存在一些细微差别details,如果您的应用程序需要符合 AA 或更高标准,请确保您了解这些细微差别。