Javascript 在ReactJS中处理set/removeAttribute和添加类列表的更好方法

Javascript 在ReactJS中处理set/removeAttribute和添加类列表的更好方法,javascript,html,css,reactjs,Javascript,Html,Css,Reactjs,我已经创建了一个自定义手风琴-完整的工作视图 这是我的handleClick功能,当你点击每个手风琴时可以使用。我需要一个动画(打开和关闭内容时),所以这就是我尝试的。我不确定这是否是一种接近我想要实现的目标的反应方式 关于如何使此函数更具反应性,有什么建议吗 const handleClick = (e) => { e.preventDefault(); const accordion = e.target.parentNode; const content

我已经创建了一个自定义手风琴-完整的工作视图

这是我的
handleClick
功能,当你点击每个手风琴时可以使用。我需要一个动画(打开和关闭内容时),所以这就是我尝试的。我不确定这是否是一种接近我想要实现的目标的反应方式

关于如何使此函数更具反应性,有什么建议吗

  const handleClick = (e) => {
    e.preventDefault();

    const accordion = e.target.parentNode;
    const content = accordion.querySelector(".content");

    if (accordion.hasAttribute("open")) {
      content.style.removeProperty("max-height");
      content.classList.add("closed");
      setTimeout(() => {
        accordion.removeAttribute("open");
      }, 400);
      return;
    }
    // If the <details> element is closed, add the [open] attribute (so the content will render), and animate in
    accordion.setAttribute("open", "");
    // Get proper max-height for element for better animation
    if (!content.getAttribute("data-height")) {
      content.style.maxHeight = "none";
      content.setAttribute(
        "data-height",
        `${content.getBoundingClientRect().height}px`
      );
      content.style.removeProperty("max-height");
    }
    // Wait for the browser to apply [open] to <details>, then animate
    setTimeout(() => {
      content.classList.remove(["closed"]);
      content.style.maxHeight = content.getAttribute("data-height");
    }, 0);
  };
const handleClick=(e)=>{
e、 预防默认值();
const accordion=e.target.parentNode;
常量内容=accordion.querySelector(“.content”);
if(accordion.hasAttribute(“打开”)){
content.style.removeProperty(“最大高度”);
content.classList.add(“已关闭”);
设置超时(()=>{
手风琴。删除属性(“打开”);
}, 400);
返回;
}
//如果元素已关闭,请添加[open]属性(以便内容将渲染),并在中设置动画
accordion.setAttribute(“打开”、“打开”);
//为元素获取适当的最大高度,以获得更好的动画效果
如果(!content.getAttribute(“数据高度”)){
content.style.maxHeight=“无”;
content.setAttribute(
“数据高度”,
`${content.getBoundingClientRect().height}px`
);
content.style.removeProperty(“最大高度”);
}
//等待浏览器应用[打开],然后设置动画
设置超时(()=>{
content.classList.remove([“closed”]);
content.style.maxHeight=content.getAttribute(“数据高度”);
}, 0);
};

我建议在渲染方法中使用状态并解释这些状态,而不是通过选择器设置属性,例如:

  const [accordionOpened, setAccordionOpened] = useState(false);
 {
   title: "Lorem ipsum dolor sit amet",
   content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pretium sagittis quam vitae commodo. Nulla et ligula non nunc ornare consectetur.",
   opened: false,
 }
如果手风琴打开或关闭,将用布尔值表示

因为您的手风琴中有多个项目,所以这不是您想要的,因为您必须为手风琴中的项目数量复制此状态

我会在您的数据项中添加一个字段,例如:

  const [accordionOpened, setAccordionOpened] = useState(false);
 {
   title: "Lorem ipsum dolor sit amet",
   content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pretium sagittis quam vitae commodo. Nulla et ligula non nunc ornare consectetur.",
   opened: false,
 }
将在渲染方法中对其进行解释,如:

{item.opened ? <p className={"openedContent"}>{item.content}</p> : null}
{item.opened?

{item.content}

:null}

然后,您将能够摆脱那些在handleClick中设置的无关的关闭和打开属性。在React中,您永远不会直接更新UI。而是更新状态,然后告诉React如何将该状态映射到UI

考虑将手风琴分为两个部分-一个
手风琴
和一个
手风琴项目
。然后,你有一个这样的结构:

const AccordionItem = ({ title, content, toggle, open }) => (
  <details open={open} onClick={toggle}>
    <summary>{title}</summary>
    <p>{content}</p>
  </details>
);

export const Accordion = (props) => {
  const [items, setItems] = useState(
    props.items.map((item) => ({
      ...item,
      open: false
    }))
  );

  const toggleItem = (idx) => (e) => {
    e.preventDefault();

    setItems([
      ...items.slice(0, idx),
      { ...items[idx], open: !items[idx].open },
      ...items.slice(idx + 1)
    ]);
  };

  return items.map((item, idx) => (
    <AccordionItem key={idx} toggle={toggleItem(idx)} {...item} />
  ));
};
const AccordionItem=({title,content,toggle,open})=>(
{title}
{content}

); 导出常数手风琴=(道具)=>{ const[items,setItems]=useState( 道具.道具.地图((道具)=>({ …项目, 开放:假 })) ); 常量切换项=(idx)=>(e)=>{ e、 预防默认值(); 设置项([ …items.slice(0,idx), {…items[idx],打开:!items[idx].open}, …items.slice(idx+1) ]); }; 返回items.map((item,idx)=>( ,但是有很多关于如何在React中使用refs的文章,所以我在这里不详细介绍


谢谢你的建议。我尝试过你的例子,尝试过在打开和关闭时添加动画-它不起作用。我尝试过各种方法,但无法复制动画。我做错了什么?