组件工坊: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.arearx.el.audiorx.el.canvasrx.el.embedrx.el.iframerx.el.imgrx.el.mathrx.el.metarx.el.objectrx.el.picturerx.el.sourcerx.el.trackrx.el.video官方文档
工坊订单
商品详情页:只用 HTML 媒体元素放入大图(窄屏时换成正方形图片)、使用视频和试听音频。
这些 HTML 元素用来把图片、视频、声音和其他文档放进页面。最常用的是 img·video·audio;用 picture·source 选择适合屏幕的文件;用 iframe·embed·object 嵌入其他文档。
它们比 Reflex 的 rx.image、rx.video、rx.audio 更简单,直接使用浏览器的原生功能。
rx.el.img(src="https://picsum.photos/id/1025/300/200", alt="A dog in a blanket", width="300px", height="200px")img 可以改变适配盒子尺寸的方式(object_fit)和 CSS 滤镜;video 可以切换控制条(controls)、循环和静音。
试着改属性
width
fit
radius
filter
loading
rx.el.img(
src="https://picsum.photos/id/1043/400/250",
alt="A city street",
width="240px",
height="160px",
object_fit="cover",
border_radius="8px",
filter="none",
loading="lazy",
background=rx.color("gray", 4),
)试着改属性
controls
loop
muted
width
rx.el.video(
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
poster="https://picsum.photos/id/152/320/180",
controls=True,
loop=False,
muted=True,
plays_inline=True,
width="280px",
)| 属性 | 取值 | 默认值 | 用途 |
|---|---|---|---|
src alt (img) | URL / 字符串 | 无 | 图片地址与替代文字。alt 一定要写 |
src_set sizes (img, source) | 候选列表 | 无 | 按屏幕密度·宽度选择文件 |
loading (img, iframe) | "lazy" "eager" | "eager" | 接近可视区域时才加载 |
decoding (img) | "async" "sync" "auto" | "auto" | 图片解码的时机 |
controls loop muted auto_play (video, audio) | True / False | False | 控制条、循环、静音、自动播放 |
poster plays_inline (video) | URL / bool | 无 | 播放前的图片;在移动端不全屏播放 |
preload (video, audio) | "none" "metadata" "auto" | 因浏览器而异 | 预先下载多少 |
media type (source) | 媒体查询 / MIME | 无 | 条件与文件格式 |
kind src_lang label default (track) | 字符串·bool | 无 | 字幕文件 |
src_doc sandbox allow (iframe) | HTML / 权限列表 | 无 | 要嵌入的文档与限制 |
shape coords href (area) | "rect" "circle" "poly" … | 无 | 图像映射中可点击的区域 |
alt 是图片加载失败时显示的文字,也是屏幕阅读器读出的文字。右边的图片故意用了本站不存在的地址,所以显示的是 alt。
给 src_set 提供 1x·2x 候选,高分辨率屏幕就会选择更大的文件。loading="lazy" 会把加载推迟到图片接近可视区域时。

rx.el.div(
rx.el.img(
src="https://picsum.photos/id/1025/150/100",
src_set="https://picsum.photos/id/1025/150/100 1x, https://picsum.photos/id/1025/300/200 2x",
alt="Sharp on high density screens",
loading="lazy",
decoding="async",
),
rx.el.img(src="/no-such-image.png", alt="Broken image: the alt text shows"),
display="flex",
gap="12px",
align_items="center",
)浏览器从上往下查看 picture 里的 source,使用第一个满足 media 条件的文件。都不满足时,使用最后的 img。
把窗口宽度缩到 640px 以下,就会换成正方形照片。
rx.el.picture(
rx.el.source(media="(max-width: 640px)", src_set="https://picsum.photos/id/1015/300/300"),
rx.el.img(src="https://picsum.photos/id/1016/480/200", alt="A landscape", max_width="100%"),
)可以直接给 src,也可以把多个不同格式的文件作为 source 子元素给出。浏览器会选择第一个能播放的 source。
source 后面的文字只在无法播放视频的浏览器中显示。大多数浏览器只允许在 muted 时自动播放(auto_play)。
rx.el.div(
rx.el.video(
rx.el.source(src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4", type="video/mp4"),
"Your browser cannot play this video.",
controls=True,
muted=True,
preload="metadata",
width="280px",
),
rx.el.audio(
src="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3",
controls=True,
preload="none",
),
display="flex",
flex_direction="column",
gap="12px",
)track 用来挂载 WebVTT(.vtt)字幕文件。字幕文件必须来自同一站点,所以这里只以代码展示。文件放在 assets 文件夹里。
rx.el.video(
rx.el.source(src="/flower.mp4", type="video/mp4"),
rx.el.track(src="/flower.en.vtt", kind="subtitles", src_lang="en", label="English", default=True),
controls=True,
)在 src 里给出另一个页面的地址,或在 src_doc 里直接写 HTML。sandbox="" 会禁止嵌入文档的脚本·表单·弹窗,再用 "allow-scripts" 这样的值只放开需要的功能。
title 告诉屏幕阅读器里面放的是什么。很多网站禁止被别人嵌入。
rx.el.iframe(
src_doc="<h3 style='font-family:sans-serif'>Hello from an iframe</h3><p style='font-family:sans-serif'>This page lives in src_doc.</p>",
sandbox="",
loading="lazy",
title="Inline document",
width="320px",
height="130px",
border="1px solid gray",
border_radius="6px",
)两者都是嵌入外部资源的老办法。embed 只接受 src 和 type;object 用 data 接收,加载失败时显示子元素作为替代。
如今图片用 img、视频用 video、文档用 iframe 更好。
rx.el.div(
rx.el.embed(src="https://picsum.photos/id/237/160/110", type="image/jpeg", width="160px", height="110px"),
rx.el.object(
"Fallback text if the data cannot load",
data="https://picsum.photos/id/40/160/110",
type="image/jpeg",
width="160px",
height="110px",
),
display="flex",
gap="12px",
)canvas 是一块空白画布,绘制工作由 JavaScript 完成。下面在 on_mount 里用 rx.call_script 画出一个矩形和一个圆。
canvas 的 width·height 不是 CSS 尺寸,而是画布的像素数,所以在 Reflex 里用 custom_attrs 传入(用关键字参数给会变成 CSS)。
rx.el.canvas(
id="htmlmedia_canvas",
custom_attrs={"width": "260", "height": "100"},
border="1px solid gray",
border_radius="6px",
on_mount=rx.call_script(
"const g = document.getElementById('htmlmedia_canvas').getContext('2d');"
" g.fillStyle = '#6e56cf'; g.fillRect(20, 20, 120, 60);"
" g.fillStyle = '#e54d2e'; g.beginPath(); g.arc(200, 50, 30, 0, Math.PI * 2); g.fill();"
),
)map 里的 area 是图片上可点击的区域。在 img 的 use_map 里写上 "#映射名" 来关联。照片的左半边和右边的圆分别链接到不同的文档。
rx.el.div(
rx.el.map(
rx.el.area(shape="rect", coords="0,0,150,200", href="https://reflex.dev/docs/library/", target="_blank", alt="Library docs"),
rx.el.area(shape="circle", coords="225,100,60", href="https://reflex.dev/docs/library/html/media/", target="_blank", alt="Media docs"),
name="htmlmedia-map",
),
rx.el.img(src="https://picsum.photos/id/1060/300/200", alt="Image map", use_map="#htmlmedia-map", width="300px", height="200px"),
)rx.el.math 是装数学公式(MathML)的盒子,但要放进去的 mi·mo·msup 等标签在 rx.el 里没有。公式用 rx.html 整段放入 MathML 更方便。
meta 是文档头部的信息。React 19 会把正文里的 meta 提升到头部,所以不要在页面里渲染它,通常用 @rx.page 的 meta 参数给出。
rx.html("<math display='block'><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup><mo>=</mo><msup><mi>c</mi><mn>2</mn></msup></math>")rx.el.math(...) # MathML box; rx.el has no mi/mo/mn tags to put inside it
rx.el.meta(name="description", content="A page about media") # for the document head
@rx.page(title="Media", description="A page about media", meta=[{"name": "theme-color", "content": "#6e56cf"}])
def media_page(): ...照片用 picture 适配屏幕,视频用 poster 和 preload="none" 在点击之前不下载,声音使用 audio 的原生控制条。
See it in action
Sound preview
rx.el.div(
rx.el.picture(
rx.el.source(media="(max-width: 640px)", src_set="https://picsum.photos/id/26/320/320"),
rx.el.img(src="https://picsum.photos/id/26/440/240", alt="Travel kit on a table", border_radius="8px", max_width="100%"),
),
rx.el.p("See it in action", font_weight="600", margin_top="8px"),
rx.el.video(
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
poster="https://picsum.photos/id/26/440/248",
controls=True,
muted=True,
plays_inline=True,
preload="none",
width="100%",
),
rx.el.p("Sound preview", font_weight="600", margin_top="8px"),
rx.el.audio(src="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3", controls=True, preload="none"),
max_width="440px",
)工坊笔记
img 一定要写 alt。用 src_set·loading="lazy" 延迟加载合适的文件。
用 picture + source(media) 按屏幕显示不同图片,最后放 img。
video·audio 用 controls 显示控制条,自动播放要配合 muted。字幕用 track。
iframe 用 src 或 src_doc,用 sandbox 加限制。embed·object 是老办法。
canvas 尺寸用 custom_attrs,绘制靠 JavaScript。meta 用 @rx.page(meta=...)。
订阅新课时和新课程通知
本课程新增课时或推出后续课程时,我们会发邮件通知你。
问答
关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。