组件工坊:Reflex 组件库 100 例
·
课程概览
布局
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
排版
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
表单
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
数据展示
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
展开与切换
·
Tabs
·
Accordion
·
Segmented Control
浮层
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
动态渲染
·
Cond
·
Match
·
Foreach
·
Auto Scroll
媒体
·
Image
·
Audio
·
Video
表格与数据网格
·
Table
·
Data Table
·
Data Editor
图表
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
图表部件
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
其他图表库
·
Plotly
·
Pyplot
HTML 元素
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
其他工具
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
rx.el.tablerx.el.captionrx.el.colgrouprx.el.colrx.el.theadrx.el.tbodyrx.el.tfootrx.el.trrx.el.thrx.el.td官方文档
工坊订单
把咖啡店收据做成表格:标题、品名·数量·价格的表头行,以及含合计的表尾行,全部用纯 HTML 表格搭出来。
这些 HTML 表格元素用来展示由行和列组成的数据。在 table 里的 tbody 中放行 tr,行里放表头单元格 th 和普通单元格 td。
它们没有样式,所以要自己加边框和内边距。需要 Radix 风格的表格就用 rx.table,需要排序·搜索的表格就用 rx.data_table。
| Name | Role |
|---|---|
| Ada | Engineer |
| Linus | Maintainer |
rx.el.table(
rx.el.tbody(
rx.el.tr(rx.el.th("Name"), rx.el.th("Role")),
rx.el.tr(rx.el.td("Ada"), rx.el.td("Engineer")),
rx.el.tr(rx.el.td("Linus"), rx.el.td("Maintainer")),
),
)本站的 preflight 会把表格单元格之间合并起来(border_collapse="collapse")。改成 separate,每个单元格的边框就会分开。
试着改属性
| Item | Qty |
|---|---|
| Apples | 3 |
| Pears | 12 |
caption
caption_side
align
collapse
rx.el.table(
rx.el.caption("Fruit stock", caption_side="top", padding="4px", font_weight="600"),
rx.el.thead(
rx.el.tr(
rx.el.th("Item", border="1px solid gray", padding="6px"),
rx.el.th("Qty", border="1px solid gray", padding="6px"),
),
),
rx.el.tbody(
rx.el.tr(
rx.el.td("Apples", border="1px solid gray", padding="6px"),
rx.el.td("3", align="right", border="1px solid gray", padding="6px"),
),
rx.el.tr(
rx.el.td("Pears", border="1px solid gray", padding="6px"),
rx.el.td("12", align="right", border="1px solid gray", padding="6px"),
),
),
border_collapse="collapse",
border_spacing="4px",
width="260px",
)| 属性 | 取值 | 默认值 | 用途 |
|---|---|---|---|
col_span (td, th) | 整数 | 1 | 横向合并的单元格数 |
row_span (td, th) | 整数 | 1 | 纵向合并的单元格数 |
scope (th) | "col" "row" "colgroup" "rowgroup" | 无 | 这个表头单元格负责的方向 |
headers (td, th) | th 的 id 列表 | 无 | 直接指定这个单元格的表头 |
align (td, th) | "left" "center" "right" "justify" "char" | 左对齐 | 单元格内对齐(旧属性,也可用 CSS text_align) |
span (col, colgroup) | 整数 | 1 | 一个 col 负责的列数 |
align summary (table) | 字符串 | 无 | HTML5 中已废弃的旧属性。对齐用 CSS,说明用 caption |
thead·tbody·tfoot 把行分成表头·表体·表尾。行一定要放进这三者之一。
如果把 tr 直接放在 table 下面,浏览器会悄悄插入一个 tbody,结构就可能和 React 所知道的不一致。
caption 是表格的标题,必须是 table 的第一个子元素。th 的 scope 表明这个表头单元格负责的是列("col")还是行("row")。
| Month | Visitors |
|---|---|
| Jan | 1,200 |
| Feb | 1,450 |
| Total | 2,650 |
rx.el.table(
rx.el.caption("Monthly visitors", padding="4px", font_weight="600"),
rx.el.thead(
rx.el.tr(rx.el.th("Month", scope="col"), rx.el.th("Visitors", scope="col")),
background=rx.color("indigo", 3),
),
rx.el.tbody(
rx.el.tr(rx.el.th("Jan", scope="row"), rx.el.td("1,200")),
rx.el.tr(rx.el.th("Feb", scope="row"), rx.el.td("1,450")),
),
rx.el.tfoot(
rx.el.tr(rx.el.th("Total", scope="row"), rx.el.td("2,650", font_weight="bold")),
border_top="2px solid gray",
),
width="280px",
text_align="left",
)col_span=2 会占掉右边一个单元格,row_span=2 会占掉下一行的一个单元格。被占掉的位置不再放 td。
下面的课程表中,第三行少一个单元格。
| Mon | Tue | Wed | |
|---|---|---|---|
| 9 am | Workshop | Free | |
| 10 am | Lunch prep | Review | Free |
| 11 am | Free | Demo | |
rx.el.table(
rx.el.thead(rx.el.tr(rx.el.th(""), rx.el.th("Mon"), rx.el.th("Tue"), rx.el.th("Wed"))),
rx.el.tbody(
rx.el.tr(rx.el.th("9 am"), rx.el.td("Workshop", col_span=2, background=rx.color("indigo", 4)), rx.el.td("Free")),
rx.el.tr(rx.el.th("10 am"), rx.el.td("Lunch prep", row_span=2, background=rx.color("amber", 4)), rx.el.td("Review"), rx.el.td("Free")),
rx.el.tr(rx.el.th("11 am"), rx.el.td("Free"), rx.el.td("Demo")),
),
border="1px solid gray",
text_align="center",
width="340px",
)colgroup 里的一个 col 负责一列,span=2 就负责两列。用来给整列设置背景色·宽度。
col 上能用的 CSS 仅限于 background、width、border、visibility 等少数几个。
| Plan | Price | Seats |
|---|---|---|
| Starter | $0 | 1 |
| Team | $20 | 10 |
rx.el.table(
rx.el.colgroup(rx.el.col(), rx.el.col(span=2)),
rx.el.thead(rx.el.tr(rx.el.th("Plan"), rx.el.th("Price"), rx.el.th("Seats"))),
rx.el.tbody(
rx.el.tr(rx.el.td("Starter"), rx.el.td("$0"), rx.el.td("1")),
rx.el.tr(rx.el.td("Team"), rx.el.td("$20"), rx.el.td("10")),
),
width="300px",
text_align="left",
# style the columns from the table: Reflex puts a <style> tag next to a styled
# element, and the browser moves a <style> found inside <colgroup> out of it
style={
"& col:first-child": {"background": rx.color("gray", 3)},
"& col:last-child": {"background": rx.color("teal", 3)},
},
)在复杂的表格中,给 th 加上 id,再在 td 的 headers 里写这个 id 来关联。页面看起来一样,但屏幕阅读器会读成 “Price, $2” 这样。
| Fruit | Price |
|---|---|
| Kiwi | $2 |
rx.el.table(
rx.el.tbody(
rx.el.tr(rx.el.th("Fruit", id="htmltable_fruit"), rx.el.th("Price", id="htmltable_price")),
rx.el.tr(rx.el.td("Kiwi", headers="htmltable_fruit"), rx.el.td("$2", headers="htmltable_price")),
),
width="200px",
text_align="left",
)行来自 State 中的列表时,用 rx.foreach 生成 tr。排序在计算变量里完成,表格直接渲染结果。
| Name | Score |
|---|---|
| Jun | 95 |
| Mina | 88 |
| Sora | 72 |
class HtmlTableScoreState(rx.State):
rows: list[dict[str, str]] = [
{"name": "Mina", "score": "88"},
{"name": "Jun", "score": "95"},
{"name": "Sora", "score": "72"},
]
descending: bool = True
@rx.event
def flip_order(self):
self.descending = not self.descending
@rx.var
def sorted_rows(self) -> list[dict[str, str]]:
return sorted(self.rows, key=lambda r: int(r["score"]), reverse=self.descending)
rx.el.div(
rx.el.button(
rx.cond(HtmlTableScoreState.descending, "High to low", "Low to high"),
on_click=HtmlTableScoreState.flip_order,
padding="4px 12px",
border="1px solid gray",
border_radius="6px",
margin_bottom="8px",
),
rx.el.table(
rx.el.thead(rx.el.tr(rx.el.th("Name"), rx.el.th("Score"))),
rx.el.tbody(
rx.foreach(
HtmlTableScoreState.sorted_rows,
lambda row: rx.el.tr(rx.el.td(row["name"]), rx.el.td(row["score"], align="right")),
),
),
width="220px",
text_align="left",
),
)caption 是收据编号,thead 是表头行,tfoot 是合计。合计的表头单元格用 col_span=2 占两列,数字列用 colgroup 统一宽度。
| Item | Qty | Price |
|---|---|---|
| Latte | 2 | $9.00 |
| Bagel | 1 | $3.50 |
| Total | $12.50 | |
rx.el.table(
rx.el.caption("Receipt #1024", padding="6px", font_weight="bold"),
rx.el.colgroup(rx.el.col(), rx.el.col(span=2)),
rx.el.thead(
rx.el.tr(rx.el.th("Item", scope="col"), rx.el.th("Qty", scope="col"), rx.el.th("Price", scope="col")),
border_bottom="2px solid gray",
),
rx.el.tbody(
rx.el.tr(rx.el.td("Latte"), rx.el.td("2", align="right"), rx.el.td("$9.00", align="right")),
rx.el.tr(rx.el.td("Bagel"), rx.el.td("1", align="right"), rx.el.td("$3.50", align="right")),
),
rx.el.tfoot(
rx.el.tr(rx.el.th("Total", scope="row", col_span=2), rx.el.td("$12.50", align="right", font_weight="bold")),
border_top="2px solid gray",
),
width="300px",
text_align="left",
font_variant_numeric="tabular-nums",
style={"& col:last-child": {"width": "70px"}}, # see the colgroup example above
)工坊笔记
table > (caption) > thead · tbody · tfoot > tr > th · td。tr 一定要放进 tbody 等元素里。
在 preflight 下,表格既没有边框也没有内边距。border·padding 要自己加。
用 col_span·row_span 合并单元格,被占掉的位置不再放单元格。
th 的 scope、td 的 headers 是为屏幕阅读器建立的关联。
行来自 State 时用 rx.foreach 生成 tr。需要带样式的表格就用 rx.table。
订阅新课时和新课程通知
本课程新增课时或推出后续课程时,我们会发邮件通知你。
问答
关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。