组件工坊: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.fieldsetrx.el.formrx.el.labelrx.el.legendrx.el.meterrx.el.optgrouprx.el.optionrx.el.outputrx.el.progressrx.el.selectrx.el.textarea官方文档
工坊订单
咖啡店点单表单:饮品从按类别分组的列表中选,取餐方式用单选,备注用多行输入,下单后显示订单摘要。
这些是与表单相关的 HTML 元素:收集输入的 form,分组框 fieldset 及其标题 legend,选择用的 select·optgroup·option,多行输入 textarea,以及显示数值的 meter·progress·output。
它们比 Radix 表单组件(rx.select、rx.text_area)更轻量,直接使用浏览器自带的行为。
rx.el.label(
"Size ",
rx.el.select(
rx.el.option("Small", value="s"),
rx.el.option("Medium", value="m"),
rx.el.option("Large", value="l"),
default_value="m",
border="1px solid gray",
padding="2px 6px",
),
)meter 会根据值处于好区间还是坏区间改变颜色。low·high 是区间的边界,optimum 决定哪一边是好的。
试着改属性
value
65
low
30
high
80
optimum
90
rx.el.div(
rx.el.meter(value=65, min=0, max=100, low=30, high=80, optimum=90, width="260px", height="20px"),
rx.el.progress(value=65, max=100, width="260px"),
display="flex",
flex_direction="column",
gap="10px",
)试着改属性
placeholder
rows
resize
disabled
read_only
rx.el.textarea(
placeholder="Write a note",
rows="4",
resize="vertical",
disabled=False,
read_only=False,
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
width="280px",
)| 属性 | 取值 | 默认值 | 用途 |
|---|---|---|---|
on_submit (form) | 事件处理器 | 无(只阻止提交) | 接收按 name 汇总值的 dict |
reset_on_submit (form) | True / False | False | 提交后清空输入 |
no_validate (form) | True / False | False | 关闭浏览器的 required·pattern 检查 |
html_for (label, output) | 元素 id | 无 | 要关联的输入框。点标签就会跳到那个输入框 |
disabled (fieldset, select, option, optgroup) | True / False | False | 禁用内部所有输入 |
value / on_change (select, textarea) | 字符串 / 事件 | 无 | 受控输入。default_value 是非受控 |
multiple size (select) | bool / 整数 | False / 无 | 多选、显示的行数 |
label (optgroup) | 字符串 | 无 | 分组标题 |
rows cols max_length (textarea) | 整数 | 无 | 尺寸与字数限制 |
auto_height enter_key_submit (textarea) | True / False | False | 随文字增高、按 Enter 提交 |
value min max low high optimum (meter) | 数字 | min=0 max=1 | 范围内的测量值 |
value max (progress) | 数字 | max=1 | 进度。没有 value 时显示为进行中 |
点击提交按钮后,on_submit 会把表单内输入框的值以 name 为键组成 dict 传入。复选框只在勾选时以 "on" 进入。
即使没有 on_submit,rx.el.form 也会阻止浏览器的默认提交(重新加载页面)。reset_on_submit=True 时,提交后清空输入框。
class HtmlFormSignupState(rx.State):
submitted: dict[str, str] = {}
@rx.event
def handle_submit(self, form_data: dict):
self.submitted = {key: str(value) for key, value in form_data.items()}
rx.el.div(
rx.el.form(
rx.el.input(name="email", type="email", placeholder="Email", required=True, border="1px solid gray", padding="4px 8px"),
rx.el.select(
rx.el.option("Weekly", value="weekly"),
rx.el.option("Monthly", value="monthly"),
name="plan",
border="1px solid gray",
padding="4px",
),
rx.el.label(rx.el.input(type="checkbox", name="news"), " Send news"),
rx.el.button("Sign up", type="submit", padding="4px 12px", border="1px solid gray", border_radius="6px"),
on_submit=HtmlFormSignupState.handle_submit,
reset_on_submit=True,
display="flex",
gap="8px",
flex_wrap="wrap",
align_items="center",
),
rx.el.ul(
rx.foreach(HtmlFormSignupState.submitted, lambda kv: rx.el.li(rx.el.code(kv[0]), " = ", kv[1])),
margin_top="10px",
),
)fieldset 用边框把相关的输入框起来,legend 是这一组的标题。给 fieldset 设置 disabled=True,里面的输入就会全部禁用。
label 可以包住输入框,也可以在 html_for 里写上输入框的 id 来关联。点击关联的标签,光标就会移到输入框里。
rx.el.div(
rx.el.fieldset(
rx.el.legend("Delivery", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="ship", value="pickup", default_checked=True), " Pickup"),
rx.el.label(rx.el.input(type="radio", name="ship", value="courier"), " Courier"),
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
),
rx.el.fieldset(
rx.el.legend("Gift wrap (sold out)", font_weight="bold"),
rx.el.label(rx.el.input(type="checkbox"), " Wrap it"),
rx.el.label("Message ", rx.el.input(id="htmlforms_gift_msg", border="1px solid gray")),
disabled=True,
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
display="flex",
gap="12px",
opacity="0.6",
),
rx.el.label("Coupon", html_for="htmlforms_coupon", margin_right="8px"),
rx.el.input(id="htmlforms_coupon", placeholder="Click the label", border="1px solid gray", padding="2px 6px"),
display="flex",
flex_direction="column",
gap="10px",
align_items="start",
)option 是可选的项目,optgroup 把项目归到 label 标题下。disabled 的项目不能选。
用 value 和 on_change 让 State 掌管选中的值。给 multiple=True 和 size,就能在展开的列表中用 Ctrl·Shift 多选。
You picked: soup
class HtmlFormSelectState(rx.State):
dish: str = "soup"
@rx.event
def change_dish(self, value: str):
self.dish = value
rx.el.div(
rx.el.select(
rx.el.optgroup(
rx.el.option("Soup", value="soup"),
rx.el.option("Salad", value="salad"),
label="Starters",
),
rx.el.optgroup(
rx.el.option("Pasta", value="pasta"),
rx.el.option("Steak (sold out)", value="steak", disabled=True),
label="Mains",
),
value=HtmlFormSelectState.dish,
on_change=HtmlFormSelectState.change_dish,
border="1px solid gray",
padding="4px",
),
rx.el.p("You picked: ", rx.el.strong(HtmlFormSelectState.dish)),
rx.el.select(
rx.el.option("Red"),
rx.el.option("Green"),
rx.el.option("Blue"),
rx.el.option("Black"),
multiple=True,
size=3,
border="1px solid gray",
width="120px",
),
display="flex",
flex_direction="column",
gap="8px",
align_items="start",
)Reflex 的 rx.el.textarea 有两个 HTML 里没有的属性。enter_key_submit=True 时,Enter 提交表单,Shift+Enter 换行。
auto_height=True 时,文字越长高度越高(配合 min_height 使用)。enter_key_submit 不能与 on_key_down 同时使用。
class HtmlFormChatState(rx.State):
messages: list[str] = []
@rx.event
def send(self, form_data: dict):
text = str(form_data.get("message", "")).strip()
if text:
self.messages = [*self.messages, text][-4:]
rx.el.div(
rx.el.ul(
rx.foreach(HtmlFormChatState.messages, lambda m: rx.el.li(m, white_space="pre-wrap")),
list_style_type="disc",
padding_left="1.5em",
),
rx.el.form(
rx.el.textarea(
name="message",
placeholder="Type and press Enter",
enter_key_submit=True,
auto_height=True,
max_length=200,
min_height="40px",
width="100%",
border="1px solid gray",
border_radius="6px",
padding="6px 8px",
),
on_submit=HtmlFormChatState.send,
reset_on_submit=True,
),
max_width="360px",
)output 是显示计算结果的位置,在 html_for 里用空格隔开写上参与计算的输入框 id。
meter 是磁盘用量这类有固定范围的测量值,progress 是任务的进度。不给 progress 设置 value,就会显示为“进行中”。
+ =
class HtmlFormOutputState(rx.State):
a: int = 2
b: int = 3
@rx.event
def change_a(self, value: float):
self.a = int(value)
@rx.event
def change_b(self, value: float):
self.b = int(value)
@rx.var
def total(self) -> int:
return self.a + self.b
rx.el.div(
rx.el.p(
rx.el.input(id="htmlforms_a", type="number", value=HtmlFormOutputState.a, on_change=HtmlFormOutputState.change_a, width="60px", border="1px solid gray"),
" + ",
rx.el.input(id="htmlforms_b", type="number", value=HtmlFormOutputState.b, on_change=HtmlFormOutputState.change_b, width="60px", border="1px solid gray"),
" = ",
rx.el.output(HtmlFormOutputState.total, html_for="htmlforms_a htmlforms_b", name="total", font_weight="bold"),
),
rx.el.label("Disk ", rx.el.meter(value=0.7, low=0.5, high=0.8, optimum=0.2, width="160px")),
rx.el.label("Loading ", rx.el.progress(width="160px")),
display="flex",
flex_direction="column",
gap="8px",
)饮品用 optgroup 分组,数量用数字输入,取餐方式是 fieldset 里的单选按钮,备注用 textarea。提交后,State 把摘要写进 output。
class HtmlFormOrderState(rx.State):
summary: str = ""
@rx.event
def place_order(self, form_data: dict):
qty = form_data.get("qty") or "1"
note = str(form_data.get("note", "")).strip() or "none"
self.summary = f"{qty} x {form_data.get('drink')} ({form_data.get('size')}), {form_data.get('pickup')}. Note: {note}"
rx.el.div(
rx.el.form(
rx.el.fieldset(
rx.el.legend("Your order", font_weight="bold"),
rx.el.select(
rx.el.optgroup(rx.el.option("Latte"), rx.el.option("Mocha"), label="Coffee"),
rx.el.optgroup(rx.el.option("Green tea"), rx.el.option("Chai"), label="Tea"),
name="drink",
border="1px solid gray",
padding="4px",
),
rx.el.select(rx.el.option("Small"), rx.el.option("Large"), name="size", border="1px solid gray", padding="4px"),
rx.el.input(name="qty", type="number", min=1, max=9, default_value=1, width="60px", border="1px solid gray", padding="4px"),
display="flex",
gap="8px",
flex_wrap="wrap",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.fieldset(
rx.el.legend("Pickup", font_weight="bold"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="for here", default_checked=True), " For here"),
rx.el.label(rx.el.input(type="radio", name="pickup", value="to go"), " To go"),
display="flex",
gap="12px",
border="1px solid gray",
border_radius="6px",
padding="8px 12px",
),
rx.el.textarea(name="note", placeholder="Notes for the barista", rows=2, border="1px solid gray", border_radius="6px", padding="6px 8px"),
rx.el.button("Order", type="submit", padding="6px 14px", border="1px solid gray", border_radius="6px", background=rx.color("indigo", 3)),
on_submit=HtmlFormOrderState.place_order,
display="flex",
flex_direction="column",
gap="10px",
),
rx.el.output(HtmlFormOrderState.summary, display="block", margin_top="10px", font_weight="600"),
max_width="420px",
)工坊笔记
rx.el.form 的 on_submit 接收 {name: 值} dict。每个输入框都要加 name。
用 fieldset + legend 分组,用 fieldset 的 disabled 一次性禁用。label 通过 html_for 关联到 id。
select 用 option·optgroup 组织,用 value + on_change 受控,用 multiple·size 多选。
textarea 的 enter_key_submit·auto_height 是 Reflex 额外提供的便利属性。
meter 是按 low·high·optimum 变色的测量值,progress 是进度,output 是计算结果。
订阅新课时和新课程通知
本课程新增课时或推出后续课程时,我们会发邮件通知你。
问答
关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。