这一课不涉及状态,只做一个静态界面。完成后,你会看到一张圆角卡片,里面是带有“Customers”标题和说明文字的页头。
tutorial_261019/ # 项目根目录(在这里执行 reflex 命令)
├── rxconfig.py # 应用名称和插件配置
├── pyproject.toml / uv.lock # Python 依赖(由 uv 管理)
├── assets/ # 图片等静态文件 → 以 "/favicon.ico" 的形式引用
├── reflex.lock/ # 界面端依赖包的锁文件(需要提交)
├── .web/ # 编译生成的 React 代码(自动生成,请勿修改)
└── tutorial_261019/ # 与 app_name 同名的 Python 包
├── __init__.py
└── tutorial_261019.py # 我们要编辑的文件(app = rx.App())rxconfig.py 的内容如下。app_name 必须和内层文件夹同名,Reflex 才能找到应用。
import reflex as rx
config = rx.Config(
app_name="tutorial_261019",
plugins=[
rx.plugins.SitemapPlugin(),
rx.plugins.TailwindV4Plugin(),
rx.plugins.RadixThemesPlugin(), # 提供按钮、表格等的默认设计
],
)清空 tutorial_261019/tutorial_261019.py 的全部内容,从下面的代码开始。
import reflex as rx
def index() -> rx.Component:
return rx.heading("Customers")
app = rx.App()
app.add_page(index, title="Customer Data App")index() 是一个返回界面片段(组件)的函数。一个页面就对应一个函数。app = rx.App() 必须写在模块的最顶层。Reflex 会通过这个变量名找到应用。index,add_page(index) 会把它注册到根路径 /。title 是浏览器标签页的标题。在浏览器中确认 — 保存后,左上角只剩下一个“Customers”标题。因为没有边距,它贴在页面边角上,这是正常的。
localhost:3000
运行效果Reflex 的界面代码,基本上就靠这两条规则:
size="6"、margin="0" 这样,以 名称=值 的形式传入。rx.box( # <div>
rx.heading("Customers", size="6"), # 子元素 1
rx.badge("2"), # 子元素 2
display="flex", # 样式
gap="12px",
)align-items → align_items,margin-top → margin_top。_:as → as_,type → type_。rx.color("slate", 11) 是 Radix 调色板。数字越大颜色越深,在深色模式下也会自动适配。通常 1~2 用于背景,4~6 用于边框,11~12 用于文字。讲师笔记 — 解释成“把 HTML 标签换成了函数调用”,学员会很快理解。rx.box = <div>,rx.text = <p>,rx.heading = <h1>~<h6>。可以打开浏览器开发者工具(F12),展示实际生成的标签。
页头分为左侧(标题 + 徽章 + 说明)和右侧(按钮)。按钮留到第4课再加,现在只做左侧。
def index() -> rx.Component:
return rx.box(
rx.box(
rx.box(
rx.heading("Customers", size="6", as_="h3", margin="0"),
rx.badge("2", variant="soft", color_scheme="gray", radius="full"),
display="flex",
align_items="center",
gap="12px",
),
rx.text(
"Your customer directory and audience breakdown.",
size="2",
color=rx.color("slate", 11),
margin_top="6px",
),
),
display="flex",
align_items="center",
justify_content="space-between",
flex_wrap="wrap",
gap="16px",
padding="24px",
)"2" 是临时值。到第3课会换成 State.users.length(),显示真实的客户数。justify_content="space-between" 会把子元素推向两端,这就是按钮会贴在最右边的原因。flex_wrap="wrap" 让按钮在屏幕较窄时换到下一行(适配移动端)。在浏览器中确认 — 标题旁边有一个灰色的圆形徽章(2),下面是灰色的说明文字。此时还没有卡片边框。
localhost:3000
运行效果Your customer directory and audience breakdown.
再用一层 rx.box 把页头包起来,做成卡片的样子。这个外层盒子就是整个应用的框架,后面的表格和图表都会依次放进来。
def index() -> rx.Component:
return rx.box(
header, # 2-4 中做好的页头 box
# 表格(第3课)、图表(第5课)会加在这里
width="100%",
min_width="0",
max_width="64em", # 卡片最大宽度
margin_x="auto", # 水平居中
margin_y="24px",
border=f"1px solid {rx.color('slate', 5)}",
border_radius="16px",
background=rx.color("slate", 1),
overflow="hidden", # 防止内容溢出圆角之外
box_shadow="0 4px 24px rgba(0, 0, 0, 0.03)",
style={
"& *": {"box_sizing": "border-box"},
"& p, & h3": {"text_align": "left"},
},
)style={...} 用于写那些难以用关键字参数表达的 CSS 选择器。"& *" 的意思是“这个盒子里的所有元素”。rx.color(...)。注意单引号和双引号要错开使用。在浏览器中确认 — 页头被放进圆角卡片中,卡片位于页面中央。把浏览器窗口拉窄,卡片宽度也会随之缩小。
localhost:3000
运行效果Your customer directory and audience breakdown.
border_radius 分别改成 "4px" 和 "32px",比较一下差异。rx.color_mode.button(),确认切换到深色模式时颜色也能自然地变化。订阅新课时和新课程通知
本课程新增课时或推出后续课程时,我们会发邮件通知你。
问答
关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。