0%

storybook使用

文中有部分名词可能不准确,见谅

本文主要介绍storybook+shadcn/ui+tailwindcss的storybook代码编写。

相关lib版本
“storybook”: “^8.2.4”,
“tailwindcss”: “^3.4.1”,

一、简介

首先,使用storybook开发一个组件需要两个文件,一个是组件*.tsx一个是story*.stories.ts/*.stories.tsx,css使用了tailwind,所以不单独进行css文件的编写。
在这里关于story文件*.stories.ts/*.stories.tsx,如果有引入组件的需求,请务必使用tsx或者jsx,否则无法识别。

二、开始

以开发一个列表为例,此列表的列表项左侧是icon+title,并且支持点击选中和点击事件。
分成两个组件开发。一个是<ListItem>,一个是<List>
先看ListItem的开发

1.ListItem

1)组件

下方是ListItem的组件代码,icon可以是导入的icon组件或者本地图片放在img标签内,这点随意。
注意,因为是tsx,所以该组件需要声明类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//ListItem.tsx
import React from 'react';

interface List{
title: string;
icon: string;
}

interface ListItemProps {
list: List;
onClick: () => void;
selected?: boolean;
}

const ListItem: React.FC<ListItemProps> = ({
list,
onClick,
selected = false,
}) => {
return(
<div
className={`flex items-center justify-between p-4 text-sm ${selected?'border-l-4 border-l-black bg-gray-500':''}`}
onClick={onClick}
>
<div className="flex items-center">
<div className="relative mr-4 size-10">
<img src={list.icon} alt=""/>
</div>
<div className="font-semibold">{list.title}</div>
</div>
</div>
)
}

这个组件接收三个参数,分别是list对象、onClick函数和select状态。根据这三个,在story文件中定义不同的story。

2)story

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//ListItem.stories.tsx
import { Meta, StoryObj } from '@storybook/react';
import ListItem from './ListItem';

const meta: Meta<typeof ListItem> = {
title: 'List/ListItem',
component: ListItem,
argTypes: {
onClick: { action: 'onClick' },
selected: { control: 'boolean' },
},
tags: ['autodocs'],
};

export default meta;

type Story = StoryObj<typeof ListItem>;

编写story文件,导入Meta生成meta,定义组件的属性。对于onClick和selected,放在argTypes中,因为需要在文档中实现这两个属性的交互。StoryObj用于生成推断类型,在生成story实例时进行类型声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//ListItem.stories.tsx
const List = {
title: "tmp1";
icon: "img1";
}

export const Default: Story = {
args: {
network: List,
selected: false,
},
};

export const Selected: Story = {
args: {
network: List,
selected: true,
},
};

上方的代码生成了两个story实例。在args中定义属性。args也可以在meta定义时声明,这样就可以得到所有story实例通用的属性。类似继承和重写。

2.List

1)组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//List.tsx
import React from 'react';
import ListItem from './ListItem';

interface List{
title: string;
icon: string;
}
interface ListProps {
lists: List[];
onSelect: () => void;
selected:string
}

const List: React.FC<ListProps> = ({
lists,
onSelect,
selected
}) => {
return (
<div className="divide-y">
{lists.map((list) => (
<ListItem
key={list.title}
list={list}
onClick={onSelect}
selected={list.title === selected}
/>
))}
</div>
);
};

export default List;

2)story

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//List.stories.tsx
import { Meta, StoryObj } from '@storybook/react';
import List from './List';

const meta: Meta<typeof List> = {
title: 'List/List',
component: List,
argTypes: {
onSelect: { action: 'onSelect' },
selected: { control: 'text' },
},
};

export default meta;

type Story = StoryObj<typeof List>;

const lists: List[] = [
{
title: 'tmp1',
icon: 'img1',
},
{
title: 'tmp2',
icon: 'img2',
},
];

export const Default: Story = {
args: {
list2,
selected: 'tmp2',
},
};