rerumaccusamus
Version:
The meta-framework suite designed from scratch for frontend-focused modern web development.
111 lines (76 loc) • 3.55 kB
Markdown
---
title: 用 CSS in JS 写组件
---
上一章节中,我们学习了如何使用 UI 组件库、标准三方库中的组件。
这一章节中,我们将学习如何实现 UI 组件。
首先我们希望自己控制联系人头像的展示,实现这种设计稿:

假设没有现成的组件可以实现,那就需要自己写些 CSS 了,传统上,我们有如下选择:
1. 直接在元素的 style 属性上写样式,缺点是:不方便维护,UI 视觉上的细节也会跟 UI 结构上的细节和业务逻辑混在一起。
2. 在 CSS 代码里用选择器找到这个头像元素,写样式,避免了 1 的缺点,但新的缺点是:不方便在其他有头像出现的地方复用,集中维护,做到 [DRY](https://en.wikipedia.org/wiki/Don't_repeat_yourself)。
3. 在 CSS 代码里写一个 classname,封装这个样式,避免了 2 的缺点,但新的缺点是:需要考虑命名问题,避免在全局命名空间下重名,可能要用到 [BEM](http://getbem.com/) 之类的规范。
4. 用 CSS Modules 技术,让 CSS 文件和其中的 classname 变得【 模块化 】,避免了 3 的缺点。
Modern.js 开箱即用的支持 CSS Modules,但我们更推荐优先采用 CSS Modules 的继承者、在【 模块化 】上更进一步的 [styled-components](https://styled-components.com/),来实现类似的需求。
Modern.js 同样开箱即用的支持 styled-components,既不需要安装依赖,也不需要做任何配置。
在 `src/App.tsx` 里修改顶部的代码:
```js
import styled from '@modern-js/runtime/styled';
```
添加以下代码:
```js
const Avatar = styled.img`
width: 50px;
height: 50px;
border: 4px solid #0ef;
border-radius: 50%;
`;
```
修改 `List.Item.Meta` 的代码:
```tsx
<List.Item.Meta
avatar={<Avatar src={avatar} />}
title={name}
description={email}
/>
```
执行 `pnpm run dev`,可以看到预期的运行结果:

接下来我们做一点重构,为了增强可读性,让代码更容易维护,可以把 Avatar 组件拆分出去
在终端执行以下命令:
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="macOS" label="macOS" default>
```bash
mkdir -p src/components/Avatar
touch src/components/Avatar/index.tsx
```
</TabItem>
<TabItem value="Windows" label="Windows">
```powershell
mkdir -p src/components/Avatar
ni src/components/Avatar/index.tsx
```
</TabItem>
</Tabs>
把 `src/App.tsx` 里的 Avatar 实现删掉,改成:
```js
import Avatar from './components/Avatar';
```
`src/components/Avatar/index.tsx` 的内容:
```js
import styled from '@modern-js/runtime/styled';
const Avatar = styled.img`
width: 50px;
height: 50px;
border: 4px solid #0ef;
border-radius: 50%;
`;
export default Avatar;
```
执行 `pnpm run dev`,运行结果应该是一样的。
:::note 注
采用目录形式(Avatar/index.tsx)而不是单文件形式(Avatar.tsx)的原因是,之后可以方便在目录内部增加子文件,包括专用的资源(图片等)、专用子组件、CSS 文件等,在这个**黑盒**内部可以随意重构,只考虑**最小局部**。
:::
---
> 本小节的代码可以在[这里查看](https://github.com/modern-js-dev/modern-js-examples/tree/main/tutorials/c06/hello-modern)。