R

ReflexKR

Reflex 官方文档

组件工坊: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

组件工坊:Reflex 组件库 100 例
表格与数据网格

Data Editor

rx.data_editorrx.data_editor_theme

官方文档

工坊订单

把咖啡馆的库存表做成像 Excel 一样点一下单元格就能直接修改,并且每次修改后都重新计算库存总额。

rx.data_editor 是像电子表格一样可以选中单元格并修改的数据网格。它用 Glide Data Grid 渲染,所以即使行和列非常多也很快。只读的表格用 Data Table 就够了;需要让用户修改数值时,才用这个组件。

columns 是每列一个 dict 组成的列表。

  • title:列标题。
  • id:列的 id。省略时取 title 转成小写后的值。
  • width:列宽(px)。
  • type:单元格的类型。可用 "str"(默认)、"int"、"float"、"bool"、"image"。
  • group:在值相同的几列上方,再画一个分组标题。

data 是每行一个列表组成的列表。每个值都要与所在列的 type 相符。

rx.data_editor(
    columns=[
        {"title": "Code", "type": "str"},
        {"title": "Value", "type": "int"},
        {"title": "Activated", "type": "bool"},
    ],
    data=[
        ["A", 1, True],
        ["B", 2, False],
        ["C", 3, False],
        ["D", 4, True],
        ["E", 5, True],
        ["F", 6, False],
    ],
)

试着改属性

点击网格,试着选中单元格、行和列。双击单元格会打开编辑框(这个实验台不保存数值,所以改过的值很快会恢复原样)。

试着改属性

row_markers

column_select

row_select

range_select

vertical_border

show_search

rx.data_editor(
    columns=[
        {"title": "Code", "type": "str"},
        {"title": "Value", "type": "int"},
        {"title": "Activated", "type": "bool"},
    ],
    data=[["A", 1, True], ["B", 2, False], ["C", 3, False], ["D", 4, True]],
    row_markers="number",
    column_select="single",
    row_select="multi",
    range_select="rect",
    vertical_border=True,
    show_search=False,
    height="220px",
)
row_markers 是行前的标记(序号·复选框),*_select 是可选择的范围,show_search 是顶部的搜索框。
属性取值用途
columns · data列表列设置、行数据
rows整数行数。省略时取 data 的长度
row_height · header_height · group_header_height整数(px)行、列标题、分组标题的高度
row_markers"none" "number" "checkbox" "both" "checkbox-visible" "clickable-number"行前标记
row_marker_start_index · row_marker_width整数行号起始值、标记列宽度
freeze_columns整数横向滚动时固定在左侧的列数
min_column_width · max_column_width · max_column_auto_width整数(px)列宽的上下限
column_select · row_select"none" "single" "multi"选择列、选择行
range_select"none" "cell" "rect" "multi-cell" "multi-rect"选择单元格范围
*_selection_blending · row_selection_mode · span_range_behavior字符串是否允许多种选择并存等细节行为
smooth_scroll_x · smooth_scroll_yTrue / False平滑滚动
vertical_border · draw_focus_ring · fixed_shadow_x · fixed_shadow_yTrue / False竖线、焦点边框、固定区域阴影
fill_handleTrue / False拖动单元格角落填充数值的手柄
get_cells_for_selectionTrue / False允许复制选中的单元格(默认 True)
overscroll_x · overscroll_y · scroll_offset_x · scroll_offset_y整数超出末尾的滚动余量、初始滚动位置
prevent_diagonal_scrolling · show_searchTrue / False禁止斜向滚动、搜索框
themerx.data_editor_theme(...) 或 dict颜色与字体
grid_selection选择 dict当前选择。使用 on_grid_selection_change 时必须一并绑定
事件接收的值触发时机
on_cell_clicked · on_cell_activated · on_cell_context_menu[列, 行]点击单元格、用 Enter 或双击激活、右键点击时
on_cell_edited[列, 行]、新单元格 dict修改单元格值时(新值在 dict["data"] 中)
on_finished_editing新单元格 dict、移动方向编辑框关闭时
on_header_clicked · on_header_context_menu[列, 行]点击、右键点击列标题时
on_header_menu_click列、位置点击列标题的菜单按钮时
on_group_header_clicked · on_group_header_context_menu · on_group_header_renamed-点击、右键点击分组标题,或重命名分组标题时
on_item_hovered[列, 行]鼠标移到单元格上时
on_grid_selection_change · on_selection_cleared选择 dict · -选择改变或被清除时
on_delete选择 dict在选中的单元格上按 Delete 键时
on_row_appended · on_column_resize · on_search_close- · 列、宽度 · -添加行、调整列宽、关闭搜索框时

图片单元格

type="image" 的列会把图片地址显示成小图。值可以是一个地址,也可以是包含多张图片的地址列表。为了让图片看得清楚,要调大 row_height。点击图片单元格会打开放大查看的窗口。

rx.data_editor(
    columns=[
        {"title": "Preview", "type": "image", "width": 120},
        {"title": "Name", "type": "str"},
    ],
    data=[
        ["https://picsum.photos/id/237/160/100", "Puppy"],
        ["https://picsum.photos/id/1025/160/100", "Pug"],
        [["https://picsum.photos/id/1084/160/100", "https://picsum.photos/id/1074/160/100"], "Two animals"],
    ],
    row_height=90,
    height="320px",
)

点击单元格时:on_cell_clicked

on_cell_clicked 以 [列, 行] 的形式传入被点击单元格的位置(都从 0 开始)。下面的列设置里有 group: "Data",所以除 Title 外的五列上方会多出一个名为「Data」的分组标题。

Cell clicked:

from typing import Any


class DataEditorClickState(rx.State):
    clicked_data: str = "Cell clicked: "
    cols: list[dict[str, Any]] = [
        {"title": "Title", "type": "str"},
        {"title": "Name", "type": "str", "group": "Data", "width": 220},
        {"title": "Birth", "type": "str", "group": "Data", "width": 150},
        {"title": "Human", "type": "bool", "group": "Data", "width": 80},
        {"title": "House", "type": "str", "group": "Data"},
        {"title": "Patronus", "type": "str", "group": "Data"},
    ]
    data: list[list[Any]] = [
        ["1", "Harry James Potter", "31 July 1980", True, "Gryffindor", "Stag"],
        ["2", "Ronald Bilius Weasley", "1 March 1980", True, "Gryffindor", "Jack Russell terrier"],
        ["3", "Hermione Jean Granger", "19 September 1979", True, "Gryffindor", "Otter"],
        ["4", "Rubeus Hagrid", "6 December 1928", False, "Gryffindor", "None"],
    ]

    @rx.event
    def click_cell(self, pos: tuple[int, int]):
        col, row = pos
        self.clicked_data = f"Cell clicked: column {col}, row {row}"


rx.vstack(
    rx.heading(DataEditorClickState.clicked_data, size="3"),
    rx.data_editor(
        columns=DataEditorClickState.cols,
        data=DataEditorClickState.data,
        on_cell_clicked=DataEditorClickState.click_cell,
        height="220px",
    ),
    width="100%",
)

保存修改的值:on_cell_edited

Data Editor 只负责让单元格可以编辑,并不会自动保存修改后的值。必须由 on_cell_edited 事件处理器接收位置和新单元格的信息,修改 State 中的 data,改动才会留在页面上。新值在 new_value["data"] 中。试着双击单元格修改数值,或者点一下 Activated 复选框。

官方文档没有给出这个事件的示例,但要做可编辑的网格,它必不可少。

Last edit: nothing yet

from typing import Any


class DataEditorEditState(rx.State):
    cols: list[dict[str, Any]] = [
        {"title": "Code", "type": "str"},
        {"title": "Value", "type": "int"},
        {"title": "Activated", "type": "bool"},
    ]
    data: list[list[Any]] = [["A", 1, True], ["B", 2, False], ["C", 3, False]]
    last_edit: str = "nothing yet"

    @rx.event
    def edit_cell(self, pos: tuple[int, int], new_value: dict[str, Any]):
        col, row = pos
        rows = [list(r) for r in self.data]
        rows[row][col] = new_value.get("data")
        self.data = rows
        self.last_edit = f"row {row}, column {col} -> {new_value.get('data')}"

    @rx.event
    def add_row(self):
        self.data = self.data + [["New", 0, False]]


rx.vstack(
    rx.data_editor(
        columns=DataEditorEditState.cols,
        data=DataEditorEditState.data,
        on_cell_edited=DataEditorEditState.edit_cell,
        row_markers="number",
        height="200px",
    ),
    rx.hstack(
        rx.button("Add row", size="1", on_click=DataEditorEditState.add_row),
        rx.text("Last edit: ", DataEditorEditState.last_edit, size="2"),
        align="center",
    ),
    width="100%",
)

定制外观:theme

把颜色和字体传给 theme。可以给 rx.data_editor_theme(...)(官方文档中是 from reflex.components.datadisplay.dataeditor import DataEditorTheme)传关键字参数,也可以直接传 dict。键名既可以用 accent_color 这样的下划线写法,也可以用 accentColor 这样的驼峰写法。下面的示例在深色主题上加了 row_height=50、平滑滚动和单列选择。

dataeditor_dark_theme = {
    "accent_color": "#8c96ff",
    "accent_light": "rgba(202, 206, 255, 0.253)",
    "text_dark": "#ffffff",
    "text_medium": "#b8b8b8",
    "text_light": "#a0a0a0",
    "text_bubble": "#ffffff",
    "bg_icon_header": "#b8b8b8",
    "fg_icon_header": "#000000",
    "text_header": "#a1a1a1",
    "text_header_selected": "#000000",
    "bg_cell": "#16161b",
    "bg_cell_medium": "#202027",
    "bg_header": "#212121",
    "bg_header_has_focus": "#474747",
    "bg_header_hovered": "#404040",
    "bg_bubble": "#212121",
    "bg_bubble_selected": "#000000",
    "bg_search_result": "#423c24",
    "border_color": "rgba(225,225,225,0.2)",
    "drilldown_border": "rgba(225,225,225,0.4)",
    "link_color": "#4F5DFF",
    "header_font_style": "bold 14px",
    "base_font_style": "13px",
}


rx.data_editor(
    columns=[
        {"title": "Code", "type": "str", "width": 120},
        {"title": "Value", "type": "int", "width": 120},
        {"title": "Activated", "type": "bool", "width": 120},
    ],
    data=[["A", 1, True], ["B", 2, False], ["C", 3, False], ["D", 4, True], ["E", 5, True]],
    row_height=50,
    smooth_scroll_x=True,
    smooth_scroll_y=True,
    column_select="single",
    theme=rx.data_editor_theme(**dataeditor_dark_theme),
    height="260px",
)

完成订单

库存表通过 on_cell_edited 保存修改,库存总额和需补货的数量写成计算变量。修改数量或单价后,下方的徽章会立刻更新。品名列用 freeze_columns=1 固定住。

Stock value: $263.60To reorder: 1
from typing import Any


class DataEditorStockState(rx.State):
    cols: list[dict[str, Any]] = [
        {"title": "Item", "type": "str", "width": 160},
        {"title": "Qty", "type": "int", "width": 80},
        {"title": "Unit price", "type": "float", "width": 110},
        {"title": "Reorder", "type": "bool", "width": 90},
    ]
    data: list[list[Any]] = [
        ["Coffee beans", 12, 18.5, False],
        ["Paper cups", 300, 0.1, False],
        ["Oat milk", 4, 2.9, True],
    ]

    @rx.event
    def edit_cell(self, pos: tuple[int, int], new_value: dict[str, Any]):
        col, row = pos
        rows = [list(r) for r in self.data]
        rows[row][col] = new_value.get("data")
        self.data = rows

    @rx.var
    def total(self) -> str:
        value = sum(float(r[1] or 0) * float(r[2] or 0) for r in self.data)
        return f"${value:,.2f}"

    @rx.var
    def reorder_count(self) -> int:
        return sum(1 for r in self.data if r[3])


rx.vstack(
    rx.data_editor(
        columns=DataEditorStockState.cols,
        data=DataEditorStockState.data,
        on_cell_edited=DataEditorStockState.edit_cell,
        row_markers="number",
        freeze_columns=1,
        height="180px",
    ),
    rx.hstack(
        rx.badge("Stock value: ", DataEditorStockState.total, size="2"),
        rx.badge("To reorder: ", DataEditorStockState.reorder_count, color_scheme="orange", size="2"),
    ),
    width="100%",
)

工坊笔记

  • columns 是 {title, type, width, id, group} 的 dict 列表,data 是行的列表。值要与列的 type 相符。

  • type:str · int · float · bool · image。

  • 修改后的值必须在 on_cell_edited((列, 行), 新单元格) 中更新 State 的 data,才会保留下来。

  • 选择范围用 column_select · row_select · range_select,行前标记用 row_markers。

  • theme=rx.data_editor_theme(...) 或 dict;大小用 height 和 row_height 设定。

← 上一课

表格与数据网格 · Data Table

下一课 →

图表 · Area Chart

订阅新课时和新课程通知

本课程新增课时或推出后续课程时,我们会发邮件通知你。

收集项目:电子邮箱 · 用途:本课程的新课时和上线通知 · 保存期限:直到你要求删除。不会用于其他用途,也不会提供给他人。回复任意通知邮件,我们会立即删除。

问答

关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。

以纯文本显示,不支持链接和格式。

R

ReflexKR

动手学 Python 和 Reflex。所有示例均已在 Reflex 0.10.0 上实际运行验证。

ReflexKR 免费,没有横幅广告。如果对你有帮助,欢迎请我们喝杯咖啡。 ☕ 请我们喝杯咖啡

联盟链接与赞助说明
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex