网络请求列表 MiniApp
加载状态、刷新、错误展示和远端数据列表。
演示 network.get 拉取 JSON、加载/错误状态与可搜索列表展示。
#预期效果
运行后会出现带加载状态的网络列表,刷新、错误展示和空状态都在同一页面闭环。
#适合场景
- API 列表、远程内容流、搜索结果页。
- 需要加载中、失败、空结果和下拉刷新状态的页面。
#页面结构
| 区域 | 结构 | 作用 |
|---|---|---|
| 顶层 | NavigationStack | 页面标题和系统搜索栏。 |
| 操作区 | Section + Button | 用户主动触发网络请求。 |
| 结果区 | Section + ForEach | 稳定渲染远程数据。 |
| 失败/空状态 | ContentUnavailableView | 避免请求失败后空白。 |
#完整示例
已复制
import appui
import network
state = appui.State(
loading=False,
error="",
query="",
items=[
{"id": "sample-1", "title": "示例数据", "subtitle": "点击刷新后替换为接口结果"},
],
)
def set_query(value):
state.query = str(value)
def load_data():
state.loading = True
state.error = ""
try:
if not network.is_connected():
state.error = "当前没有网络连接"
return
resp = network.get("https://jsonplaceholder.typicode.com/posts", timeout=15)
if not resp.ok:
state.error = f"HTTP {resp.status}"
return
data = resp.json()
rows = []
for item in data[:20]:
rows.append({
"id": str(item.get("id", len(rows))),
"title": str(item.get("title", "Untitled")),
"subtitle": str(item.get("body", ""))[:120],
})
state.items = rows
except Exception as exc:
state.error = str(exc)
finally:
state.loading = False
def filtered_items():
q = state.query.strip().lower()
if not q:
return state.items
return [
item for item in state.items
if q in item["title"].lower() or q in item["subtitle"].lower()
]
def item_key(item):
return item["id"]
def row(item):
return appui.VStack(
[
appui.Text(item["title"]).font("headline"),
(
appui.Text(item["subtitle"])
.font("subheadline")
.foreground_color("secondaryLabel")
.line_limit(2)
),
],
alignment="leading",
spacing=4,
)
def body():
result_items = filtered_items()
result_content = []
if state.loading:
result_content.append(appui.ProgressView("正在加载..."))
elif state.error:
result_content.append(
appui.ContentUnavailableView(
"请求失败",
system_image="wifi.exclamationmark",
description=state.error,
)
)
elif not result_items:
result_content.append(
appui.ContentUnavailableView(
"没有结果",
system_image="doc.text.magnifyingglass",
description="换个关键词或点击刷新数据。",
)
)
else:
result_content.append(appui.ForEach(result_items, row_builder=row, key=item_key))
return appui.NavigationStack(
appui.List(
[
appui.Section(
[
appui.Button("刷新数据", action=load_data)
.button_style("bordered_prominent"),
],
header="API",
footer="示例接口仅用于演示,请替换为自己的 API。",
),
appui.Section(result_content, header="结果"),
]
)
.searchable(text=state.query, on_change=set_query)
.refreshable(load_data)
.navigation_title("网络列表")
)
appui.run(body, state=state, presentation="fullscreen_with_close")
#关键技巧
- 在按钮回调里发起请求,不要在
body()里直接请求。 resp.ok只表示 HTTP 成功,业务字段仍需自行校验;失败时把error文案显示出来避免空白页。- 动态远程数据使用
ForEach(..., key=...),不要直接把筛选后的下标当身份。
#可替换点
| 当前写法 | 可替换为 |
|---|---|
| 演示接口 | 你的业务 API |
network.get(...) | network.request(...) / network.post(...) |
state.items | storage.get_json(...) 作为离线缓存 |