[英]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:如果您对其进行测试,您会发现一些问题:
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.我将按照您介绍问题的顺序进行。
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>
);
}
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 设为绝对值,使其宽度不会与布局和过渡混淆。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: flex
和flexGrow: 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.