文章目录
前言
前面我们通过改造App.tsx
设计了应用的布局,但总不能把整个应用的代码都塞进App.tsx
里。这章开始,我们要通过组件的方式重新组织代码,让代码可读性更好,也更方便扩展。
一、新的代码结构
先在src
下新建一个目录components
,这里放置各个组件,然后再把这些组件拼凑成应用。
前面布局的时候我们提到,会有Menu
SideBar
ToolBar
Footer
Content
这几个部分。我们再进一步将Content
分为画布区(Canvas
)和属性区(Attrs
),再挂上一个WidgetBar
。现在我们就为分别为它们创建对应的组件(和文件)并放在components
下。以下就是新的代码结构:
├── App.tsx
├── assets
│ └── react.svg
├── components
│ ├── attrs.tsx
│ ├── canvas.tsx
│ ├── content.tsx
│ ├── footer.tsx
│ ├── layout.tsx
│ ├── menu.tsx
│ ├── sidebar.tsx
│ ├── toolbar.tsx
│ └── widgetbar.tsx
├── main.tsx
├── styles
│ └── index.scss
├── styles.css
└── vite-env.d.ts
二、组件化应用
接下来,我们依次创建对应的组件。
2.1 Menu
interface MenuProps {
className?: string;
}
export const Menu: React.FC<MenuProps> = ({ className }) => {
return <div className={`h-10 ${className ?? ""}`}></div>;
};
2.2 SideBar
interface SideBarProps {
className?: string;
}
export const SideBar: React.FC<SideBarProps> = ({ className }) => {
return <div className={className ?? ""}></div>;
};
2.3 ToolBar
interface ToolBarProps {
className?: string;
}
export const ToolBar: React.FC<ToolBarProps> = ({ className }) => {
return <div className={className ?? ""}></div>;
};
2.4 Footer
interface FooterProps {
className?: string;
}
export const Footer: React.FC<FooterProps> = ({ className }) => {
return <div className={`h-10 ${className ?? ""}`}></div>;
};
2.5 Content
Content
分为画布区(Canvas
)和属性区(Attrs
),再挂上一个WidgetBar
。
import { Attrs } from "./attrs";
import { Canvas } from "./canvas";
import { WidgetBar } from "./widgetbar";
interface ContentProps {
className?: string;
}
export const Content: React.FC<ContentProps> = ({ className }) => {
return (
<div className={`relative h-full ${className ?? ""}`}>
<WidgetBar />
<div className="flex h-full">
<div className="flex-1 flex justify-center items-center">
<Canvas className="w-[360pt] h-[240pt] bg-white" />
</div>
<div className="w-[2px] h-full bg-gray-950" />
<Attrs />
</div>
</div>
);
};
2.6 WidgetBar
interface WidgetBarProps {
className?: string;
}
export const WidgetBar: React.FC<WidgetBarProps> = ({ className }) => {
return (
<div
className={`absolute left-3 top-3 w-12 h-80 bg-gray-700 rounded-md ${
className ?? ""
}`}
></div>
);
};
2.7 Canvas
interface CanvasProps {
className?: string;
}
export const Canvas: React.FC<CanvasProps> = ({ className }) => {
return <div className={className ?? ""}></div>;
};
2.8 Attrs
interface AttrsProps {
className?: string;
}
export const Attrs: React.FC<AttrsProps> = ({ className }) => {
return <div className={`w-1/5 min-w-[240px] ${className ?? ""}`}></div>;
};
2.9 AppLayout
我们把之前App的布局代码抽取成一个组件AppLayout
(layout.tsx
),这样在其它界面也可以复用。为了看起来不像之前那么丑,我们也做了一些调整。
interface AppLayoutProps {
menu: React.ReactNode;
sidebar: React.ReactNode;
toolbar: React.ReactNode;
content: React.ReactNode;
footer: React.ReactNode;
}
export const AppLayout: React.FC<AppLayoutProps> = ({
menu,
sidebar,
toolbar,
content,
footer,
}) => {
return (
<div className="flex flex-col h-screen bg-gray-500">
<div className="w-full">{menu}</div>
<div className='h-[2px] bg-gray-950' />
<div className="flex-1 flex w-full">
<div className="w-[200px]">{sidebar}</div>
<div className='w-[2px] bg-gray-950' />
<div className="flex-1 flex flex-col">
<div>{toolbar}</div>
<div className="flex-1">{content}</div>
<div className='h-[2px] bg-gray-950' />
<div>{footer}</div>
</div>
</div>
</div>
);
};
2.10 App
改造后的App.tsx
变成这个样子:
import { Canvas } from './components/canvas';
import { Footer } from './components/footer';
import { AppLayout } from './components/layout';
import { Menu } from './components/menu';
import { SideBar } from './components/sidebar';
import { ToolBar } from './components/toolbar';
import "./styles/index.scss";
function App() {
return (
<AppLayout
menu={<Menu />}
sidebar={<SideBar />}
toolbar={<ToolBar />}
content={<Canvas />}
footer={<Footer />}
/>
);
}
export default App;
现在我们的应用运行起来是这个样子的(深灰色的区块是WidgetBar
):
这看起来就稍微正经点了。如果你看着还不够顺眼,那就撸起袖子改造它吧。
总结
至此,我们的应用布局工作就告一段落了,我们会有一段时间不会去动到App.tsx
这个入口文件。接下去,我们将往各个区域添加内容,不断地拆解Menu
SideBar
ToolBar
等这些组件。而随着代码越来越多,我们还会根据需要进行代码重构。
你有没有发现,除了在App.tsx
中引入styles/index.scss
,我们没有再引入任何其它的*.scss
(或*.css/*.less
)文件。在上一章节我们留下的问题“为什么要消灭样式文件”,你有答案了吗?