简体   繁体   English

Css 书籍布局(水平手风琴)

[英]Css book layout (horizontal accordion)

I'm trying to create a page with a book layout, so a page with some tabs that use can expand one at a time.我正在尝试创建一个带有书籍布局的页面,因此一个带有一些标签的页面可以一次展开一个。

Here a working example: https://codesandbox.io/s/book-layout-l28gh?file=/src/App.js:0-1419这是一个工作示例: https://codesandbox.io/s/book-layout-l28gh?file=/src/App.js:0-1419

 import { useState } from "react"; const dataset = [ { name: "A section", description: "page A" }, { name: "B section", description: "page B" }, { name: "C section with long title", description: "page C" }, { name: "D section", description: "page D" } ]; export default function App() { return <Page />; } function Page({}) { const [openSection, setOpenSection] = useState(0); return ( <div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }} > {dataset.map((datum, i) => { const { name } = datum; const isOpen = i === openSection; return ( <div key={name} style={{ height: "100%", backgroundColor: isOpen? "white": "lightgray", border: `1px solid ${isOpen? "white": "black"}`, padding: 10, flex: 1, flexGrow: isOpen? 1: 0, transition: "all 2s ease" }} > <div style={{ cursor: "pointer", writingMode: isOpen? "horizontal-tb": "vertical-rl", transition: "all 2s ease" }} onClick={() => setOpenSection(i)} > {name} </div> </div> ); })} </div> ); }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

If you test it, you can notice some problems:如果您对其进行测试,您会发现一些问题:

  1. when you expand a section, the title doesn't make a smooth transition with it pass to be vertical to horizontal.当您展开一个部分时,标题不会平滑过渡,因为它会从垂直变为水平。 It should be a smooth rotation应该是平稳的旋转
  2. sometimes, I didn't understand exactly when, when you click a title, all the card seems to get closer to each other.有时,我不明白什么时候,当您单击标题时,所有卡片似乎彼此靠近。
  3. another request is make the grey area all clickable but it is obvious a problem when it is open另一个要求是让灰色区域全部可点击,但是当它打开时很明显是个问题

Why?为什么? What's the problem?有什么问题? It there a better approach to do a layout like this?有更好的方法来做这样的布局吗?

I will follow the same order in which you introduced your problems.我将按照您介绍问题的顺序进行。

  1. writing-mode which you're using on the titles, cannot be animated.您在标题上使用的写作模式无法设置动画。 You could try rotating the text instead using the transform property您可以尝试使用transform属性来旋转文本
  2. If you want to make the whole grey area clickable, you should move both the onClick function and the cursor: "pointer" property to the parent div of that exact element which is the title.如果要使整个灰色区域可单击,则应将onClick function 和cursor: "pointer"属性移动到父元素的确切标题。

try this to your code for grey part area clickable and ease in transition试试这个你的代码灰色部分区域可点击和易于过渡

import { useState } from "react";

const dataset = [
  { name: "A section" },
  { name: "B section" },
  { name: "C section with long title" },
  { name: "D section" },
  { name: "E section" }
];

export default function App() {
  return <Page />;
}

function Page({}) {
  const [openSection, setOpenSection] = useState(0);

  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        height: "100vh"
      }}
    >
      {dataset.map((datum, i) => {
        const { name } = datum;
        const isOpen = i === openSection;

        return (
          <div
            key={name}
            style={{
              height: "100%",
              backgroundColor: isOpen ? "white" : "lightgray",
              border: `1px solid ${isOpen ? "white" : "black"}`,
              padding: 10,
              flex: 1,
              flexGrow: isOpen ? 1 : 0,
              cursor: "pointer",
              writingMode: isOpen ? "horizontal-tb" : "vertical-rl",
   transition: "all 2s ease"
            }}
          >
            <div
              style={{
               transition: "all 2s ease"
              }}
              onClick={() => setOpenSection(i)}
            >
              {name}
            </div>
          </div>
        );
      })}
    </div>
  );
}
  1. Smooth transition : add white-space:nowrap so that the text wont shrink when size reduces.平滑过渡:添加white-space:nowrap以便文本在缩小时不会缩小。 Make title div's position absolute so that it's width won't mess with layout and transition.将标题 div 的 position 设为绝对值,使其宽度不会与布局和过渡混淆。
  2. click bug : Couldn't reproduce.单击错误:无法重现。 Sometimes the codesandbox doesn't update properly.有时代码框无法正确更新。 You need to refresh the output page and test again.需要刷新output页面重新测试。 Check with my updated code if it happens there too.如果它也发生在那里,请检查我更新的代码。
  3. make gray area clickable : move the mouse pointer and the click handler to parent with isOpen condition.使灰色区域可点击:将鼠标指针和点击处理程序移动到具有 isOpen 条件的父级。

Modified codesandbox : 修改后的代码框

import { useState } from "react";

const dataset = [
  { name: "A section" },
  { name: "B section" },
  { name: "C section with long title" },
  { name: "D section" },
  { name: "E section" }
];

export default function App() {
  return <Page />;
}

function Page({}) {
  const [openSection, setOpenSection] = useState(0);

  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        height: "100vh"
      }}
    >
      {dataset.map((datum, i) => {
        const { name } = datum;
        const isOpen = i === openSection;

        return (
          <div
            key={name}
            style={{
              height: "100%",
              backgroundColor: isOpen ? "white" : "lightgray",
              border: `1px solid ${isOpen ? "white" : "black"}`,
              flex: 1,
              flexGrow: isOpen ? 1 : 0,
              transition: "all 2s ease",

              //my changes
              padding: 0,
              flexBasis: "1.2rem",
              cursor: !isOpen ? "pointer" : "auto",
              position: "relative"
            }}
            onClick={!isOpen ? () => setOpenSection(i) : null}
          >
            <div
              style={{
                transition: "all 2s ease",

                //my changes
                transform: `rotate(${isOpen ? "0" : "90"}deg) 
                translateX(${isOpen ? "0" : "50"}%)`,
                whiteSpace: "nowrap",
                width: isOpen ? "100%" : "1rem",
                position: "absolute",
                top: isOpen ? "1rem" : "0",
                left: isOpen ? "1rem" : "0",
                fontWeight: "bold"
              }}
            >
              {name}
            </div>
          </div>
        );
      })}
    </div>
  );
}

I fixed all of your problems as you said.正如你所说,我解决了你所有的问题。

Problem #1 -> solved: you should use white-space:nowrap .问题 #1 -> 已解决:您应该使用white-space:nowrap if your text is large so in end of your box it will break to the next line.如果您的文本很大,那么在您的框的末尾它将中断到下一行。 white-space:nowrap don't let that. white-space:nowrap不要这样。 (I don't recommend that cause this is not good for too long title text.) (我不建议这样做,因为这对于太长的标题文本不利。)

Problem #2 -> solved: happens when you click some item and in middle of action (opening box) click on another one.问题 #2 -> 已解决:当您单击某个项目并在操作中间(打开框)单击另一个项目时发生。 this is because of display: flex and flexGrow: 1 .这是因为display: flexflexGrow: 1

you used flex box and justifyContent: "center" .你使用了 flex box 和justifyContent: "center" so when you click and click on another one your wrapper getting smaller and all the cards seem to get closer to each other.因此,当您单击并单击另一个时,您的包装会变小,并且所有卡片似乎都彼此靠近。 flexGrow: 1 will break them. flexGrow: 1会破坏它们。 so flexGrow: 5 is solution.所以flexGrow: 5是解决方案。

Problem #3 -> solved: wrong place to set onClick .问题 #3 -> 已解决:设置onClick的位置错误。 you should set onClick event on your box not on your text.你应该在你的盒子上而不是在你的文本上设置onClick事件。 and a condition for cursor is what you want. cursor 的条件就是你想要的。 (item is selected so cursor must be default otherwise must be poiner ). (项目被选中,所以 cursor 必须是default ,否则必须是poiner )。

Bonus:) if you set a small width to your wrapper so your rotate box will be prettier.奖励:)如果你为你的包装设置一个小宽度,那么你的旋转框会更漂亮。 it rotates at start of text and bingo.它在文本和宾果游戏的开头旋转。

import { useState } from "react";

const dataset = [
  { name: "A section" },
  { name: "B section" },
  { name: "C section with long title" },
  { name: "D section" },
  { name: "E section" },
];

function Page() {
  const [openSection, setOpenSection] = useState(1);

  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        height: "100vh",
      }}
    >
      {dataset.map((datum, i) => {
        const { name } = datum;
        const isOpen = i === openSection;
        return (
          <div
            key={name}
            onClick={() => setOpenSection(i)}
            style={{
              height: "100%",
              backgroundColor: isOpen ? "white" : "lightgray",
              border: `1px solid ${isOpen ? "white" : "black"}`,
              padding: "20px 30px",
              flex: 1,
              flexGrow: isOpen ? 5 : 0,
              transition: "all 1s linear",
              boxSizing: "border-box",
              cursor: openSection !== i ? 'pointer' : 'default',

              "&:first-child": {
                left: 0,
              },

              "&:last-child": {
                right: 0,
              },
            }}
          >
            <div
              style={{
                transform: `rotate(${isOpen ? "0" : "90"}deg)`,
                transition: "all 1s linear",
                width: 1,
                whiteSpace: "nowrap",
              }}
            >
              {name}
            </div>
          </div>
        );
      })}
    </div>
  );
}

export default Page;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM