在 Tailwind/Alpine.js 手风琴上切换 class

Toggling a class on a Tailwind/Alpine.js accordion

我用 TailwindCSS 和 Alpine.js 创建了一个手风琴,除了我还想更改按钮中的图标以在单击时展开内容外,它工作正常。

这是我的:

<div x-data="{selected:null,open:true}">

  <dl class="faqs mx-auto max-w-2xl">
    <dt>
      <span class="faq-q">Question</span>
      <button
        type="button"
        class="faq-toggle"
        @click="selected !== 1 ? selected = 1 : selected = null, open = open"
        :class="{ 'faq-open': open, 'faq-close': !(open) }"
      >
        <span>+</span>
        <span class="hidden">-</span>
      </button>
    </dt>
    <dd
      class="faq-a overflow-hidden transition-all max-h-0 duration-700"
      style="" x-ref="container1" x-bind:style="selected == 1 ? 'max-height: ' + $refs.container1.scrollHeight + 'px' : ''"
    >
      <div class="inner">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure rerum in tempore sit ducimus doloribus quod commodi eligendi ipsam porro non fugiat nisi eaque delectus harum aspernatur recusandae incidunt quasi.
      </div>
    </dd>
  </dl>
</div>

和 link 到 CodePen

我想要做的是在单击按钮时将按钮的 class 从 faq-open 切换为 faq-close。尽管我实际上可能也需要在父级 dt 上切换 class。

目前,单击按钮时手风琴展开,但 class 没有改变。

问题出在这一行

@click="selected !== 1 ? selected = 1 : selected = null, open = open"

你永远不会改变open的值,它总是初始化时的值,即open: true

你需要切换它:

@click="selected !== 1 ? selected = 1 : selected = null, open = !open"

顺便说一句,你不需要额外的变量selected来控制隐藏文本,一个open变量就足够了。像这样:

<div x-data="{open: true}">
    <dl class="faqs mx-auto max-w-2xl">
      <dt>
        <span class="faq-q">Question</span>
        <button
          type="button"
          class="faq-toggle"
          @click="open = !open"
          :class="open ? 'faq-open' : 'faq-close'"
        >
          <span :class="open ? '' : 'hidden'">+</span>
          <span :class="open ? 'hidden' : ''">-</span>
        </button>
      </dt>
      <dd
        class="faq-a overflow-hidden transition-all max-h-0 duration-700"
        style="" x-ref="container1" x-bind:style="open ? 'max-height: ' + $refs.container1.scrollHeight + 'px' : ''"
      >
        <div class="inner">
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure rerum in tempore sit ducimus doloribus quod commodi eligendi ipsam porro non fugiat nisi eaque delectus harum aspernatur recusandae incidunt quasi.
        </div>
      </dd>
    </dl>
import 'twin.macro';
import React, { useRef, useState } from 'react';
import { BiPlus, BiMinus } from 'react-icons/bi';

const Accordion = ({ title, children }) => {
  const [active, setActive] = useState(false);
  const [height, setHeight] = useState('0px');

  const contentSpace = useRef(null);
  function toggleAccordion() {
    setActive(!active);
    setHeight(active ? '0px' : `${contentSpace.current?.scrollHeight}px`);
  }

  return (
    <div tw="flex flex-col outline-none" role="button" tabIndex={0}>
      <div
        tw="flex flex-row items-center justify-between py-4 border-b border-t border-black "
        onClick={toggleAccordion}>
        <h1 tw="cursor-pointer text-base font-bold">{title}</h1>
        {active ? <BiMinus /> : <BiPlus />}
      </div>
      <div
        ref={contentSpace}
        style={{ maxHeight: `${height}` }}
        tw="overflow-auto overflow-y-hidden duration-700 ease-in-out">
        <p tw="my-4">{children}</p>
      </div>
    </div>
  );
};
export default Accordion;