3. Streamlit基础组件:文本元素与交互控件
Streamlit 的核心设计哲学是“用纯 Python 脚本快速构建数据应用”,它提供了一套丰富的内置组件,让开发者无需编写 HTML、CSS 或 JavaScript 即可完成前端界面的搭建。本章将系统讲解 Streamlit 中最基础也最常用的两类组件:文本元素(用于信息展示)与交互控件(用于用户输入)。掌握这些组件的用法、参数和适用场景,是构建任何复杂数据应用的第一步。我们将从核心原理出发,结合操作流程、实战案例与常见误区,帮助你建立扎实的组件使用能力。
上图展示了本章的核心知识框架。Streamlit 的文本元素负责将信息以结构化、美观的方式呈现给用户,而交互控件则负责捕获用户的输入并触发应用逻辑。两者结合,构成了数据应用“展示-交互-反馈”闭环的基础。下面我们将逐一深入讲解。
3.1 文本元素:构建清晰的信息层级
3.1.1 核心原理:从标题到公式的完整表达
Streamlit 的文本元素设计遵循“渐进式披露”原则:通过不同层级的标题组织内容结构,通过正文和说明文字传递细节,通过代码块和公式展示技术内容。这些元素在底层都会被转换为 HTML 渲染在浏览器中,但开发者无需关心转换细节。理解每个函数的适用场景,是高效使用它们的前提。
| 函数 | 作用 | 典型场景 | 注意事项 |
|---|---|---|---|
st.title() | 一级标题,页面主标题 | 应用首页大标题 | 一页建议仅使用一次 |
st.header() | 二级标题,章节标题 | 功能模块分区 | 保持层级清晰 |
st.subheader() | 三级标题,小节标题 | 子模块划分 | 不要过度嵌套 |
st.caption() | 小号说明文字 | 图表注释、数据来源说明 | 适合辅助信息 |
st.text() | 纯文本,无格式 | 固定格式的日志或提示 | 不支持 Markdown |
st.code() | 代码块,带语法高亮 | 展示 Python/SQL 等代码 | 可指定语言 |
st.markdown() | Markdown 富文本 | 混合排版、加粗、列表、链接 | 最常用的文本方法 |
st.latex() | LaTeX 数学公式 | 展示统计公式、算法推导 | 使用 $...$ 或 $$...$$ |
st.write() | 通用写入函数 | 自动判断类型并渲染 | 适合快速调试 |
3.1.2 操作流程:文本元素的正确使用姿势
在实际开发中,建议按照以下流程组织文本内容:
- 规划层级:先确定页面需要几个信息层级,用
st.title定义主标题,st.header定义大章节,st.subheader定义小章节。 - 填充内容:对于段落文字,优先使用
st.markdown,因为它支持 Markdown 语法,可以方便地添加加粗、斜体、链接、列表等格式。 - 嵌入技术内容:当需要展示代码时,使用
st.code并指定语言(如language="python");当需要展示数学公式时,使用st.latex。 - 补充辅助信息:对于图表下方的注释、数据来源说明等,使用
st.caption以弱化视觉权重。 - 快速调试:在开发初期,可以使用
st.write直接输出变量,它会自动识别数据类型(DataFrame、dict、list 等)并选择合适的渲染方式。
import streamlit as st
# 页面主标题
st.title("📊 销售数据分析仪表盘")
# 章节标题
st.header("一、数据概览")
# 正文内容,支持 Markdown
st.markdown("""
本模块展示 **2024 年度** 各区域的销售情况。
- 数据来源:ERP 系统导出
- 更新频率:每日凌晨 2 点
""")
# 代码块展示
st.code("""
import pandas as pd
df = pd.read_csv("sales.csv")
print(df.head())
""", language="python")
# 公式展示
st.latex(r"销售额 = \sum_{i=1}^{n} 单价_i \times 数量_i")
# 辅助说明
st.caption("注:以上数据已剔除退货订单。")
3.1.3 案例拆解:构建一个数据报告页面
假设我们需要为业务团队构建一个“月度销售报告”页面。初始需求是:展示标题、关键指标说明、数据处理的代码逻辑以及计算公式。我们按照上述流程操作:
- 使用
st.title设置“2024年6月销售报告”作为主标题。 - 使用
st.header划分“核心指标”、“数据处理流程”、“计算公式”三个章节。 - 在“核心指标”中,使用
st.markdown列出销售额、订单量、客单价等指标,并加粗关键数字。 - 在“数据处理流程”中,使用
st.code展示数据清洗的 Python 代码。 - 在“计算公式”中,使用
st.latex展示客单价的计算公式。 - 最后用
st.caption注明数据截止时间。
这样构建的页面层级分明,业务人员可以快速定位所需信息,技术人员也能清晰理解数据逻辑。
st.markdown 支持 HTML 标签,但出于安全考虑,Streamlit 会过滤部分危险标签(如 <script>)。对于简单的样式调整(如字体颜色),可以使用 <span style="color:red">文字</span>,但不要过度依赖,保持内容与样式分离更利于维护。
3.2 交互控件:让应用响应用户操作
3.2.1 核心原理:控件即变量
Streamlit 的交互控件遵循一个简单而强大的模型:每个控件函数都返回当前的值,且该值在脚本每次重新运行时都会被重新计算。当用户操作控件(如点击按钮、勾选复选框)时,Streamlit 会检测到状态变化,并从上到下重新执行整个脚本,同时将控件的新值注入到对应的变量中。这种“无回调”的编程模型极大地简化了开发流程,但也要求开发者理解“脚本即应用”的思维模式。
| 控件函数 | 返回类型 | 关键参数 | 典型应用 |
|---|---|---|---|
st.button | bool(是否被点击) | label, key | 触发一次性动作,如“加载数据” |
st.checkbox | bool(是否勾选) | label, value(默认值) | 显示/隐藏高级选项 |
st.radio | 选中的选项值 | options, index(默认选中项) | 在少量互斥选项中选择 |
st.selectbox | 选中的选项值 | options, index | 从下拉列表中选择 |
st.multiselect | 选中的选项列表 | options, default | 从多个选项中选择若干项 |
st.slider | 数值或数值范围 | min_value, max_value, value | 筛选数值范围 |
3.2.2 操作流程:从控件到业务逻辑
使用交互控件构建功能的基本流程如下:
- 确定输入需求:明确用户需要提供哪些信息。例如,是选择城市、筛选价格区间,还是触发数据刷新。
- 选择合适的控件:根据选项数量和数据特征选择控件。选项少于 5 个时用
st.radio;选项较多时用st.selectbox;需要多选时用st.multiselect;需要开关状态时用st.checkbox;需要触发动作时用st.button。 - 获取控件返回值:将控件函数赋值给变量,后续逻辑直接使用该变量。
- 编写条件逻辑:根据控件的值(如按钮是否被点击、复选框是否勾选)决定执行哪些代码块。
- 设置 key 参数:为每个控件指定唯一的
key,这有助于 Streamlit 在复杂应用中维护控件状态,避免因变量名冲突导致异常。
import streamlit as st
# 按钮:触发数据加载
if st.button("加载最新数据", key="load_btn"):
# 这里执行数据加载逻辑
st.session_state["data_loaded"] = True
st.success("数据加载完成!")
# 复选框:控制是否显示高级设置
show_advanced = st.checkbox("显示高级筛选", value=False)
if show_advanced:
# 高级筛选选项
min_price = st.slider("最低价格", 0, 1000, 100)
max_price = st.slider("最高价格", 0, 2000, 500)
st.write(f"价格区间:{min_price} - {max_price}")
# 单选:选择分析维度
dimension = st.radio("分析维度", ["按区域", "按产品线", "按渠道"], index=0)
# 多选:选择要展示的指标
metrics = st.multiselect("选择指标", ["销售额", "订单量", "利润", "退货率"], default=["销售额", "利润"])
# 下拉选择:选择具体城市
city = st.selectbox("选择城市", ["北京", "上海", "广州", "深圳"], index=0)
3.2.3 实战场景:构建一个可交互的数据筛选面板
我们以一个电商数据分析应用为例。业务人员需要根据不同的条件筛选订单数据并查看汇总结果。初始界面包含一个“数据加载”按钮、一组筛选控件和一个“生成报告”按钮。
具体实现步骤:
- 页面加载时,显示“点击加载数据”按钮。点击后,模拟从数据库读取 10 万条订单记录,并缓存到
st.session_state中。 - 数据加载完成后,显示筛选控件:
st.selectbox选择省份,st.multiselect选择商品类别,st.slider选择订单金额范围。 - 每次筛选条件变化,页面自动重新执行,并基于当前条件过滤数据,使用
st.metric展示总销售额、总订单数等关键指标。 - 点击“生成报告”按钮后,将过滤后的数据生成 CSV 下载链接。
这个案例中,控件与业务逻辑紧密耦合,每次交互都会触发数据重算。为了提升性能,可以使用 @st.cache_data 装饰器缓存数据加载函数,避免重复读取数据库。
st.cache_data 或 st.cache_resource 进行缓存,或者将计算逻辑放在按钮触发的回调中,避免频繁重算。
3.3 常见误区与总结复盘
3.3.1 误区一:混淆 st.text 与 st.markdown
st.text 用于输出纯文本,不支持任何 Markdown 语法,适合展示日志或固定格式内容。而 st.markdown 支持丰富的格式。初学者常误用 st.text 写包含 **加粗** 的文本,结果原样输出。正确做法是:需要格式化时用 st.markdown,不需要时用 st.text。
3.3.2 误区二:忽略控件的 key 参数
在复杂应用中,如果多个控件使用相同的变量名,或者控件在条件分支中被创建/销毁,可能会导致状态混乱。为每个控件指定唯一的 key 可以确保 Streamlit 正确追踪其状态。例如:
# 错误示例:两个按钮使用相同 label,可能导致状态冲突
if st.button("确定"):
pass
if st.button("确定"):
pass
# 正确示例:使用 key 区分
if st.button("确定", key="btn1"):
pass
if st.button("确定", key="btn2"):
pass
3.3.3 误区三:在循环中创建控件
在 for 循环中直接创建控件会导致 Streamlit 无法正确匹配控件状态,因为每次循环生成的控件 key 可能重复。如果需要在循环中生成多个控件,必须为每个控件指定唯一的 key,例如使用循环索引拼接 key 字符串。